odxtools 5.2.6__py3-none-any.whl → 5.3.1__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.
- odxtools/basicstructure.py +2 -2
- odxtools/cli/browse.py +18 -20
- odxtools/cli/dummy_sub_parser.py +3 -3
- odxtools/cli/main.py +1 -1
- odxtools/compumethods/compuscale.py +1 -2
- odxtools/compumethods/createanycompumethod.py +0 -1
- odxtools/compumethods/identicalcompumethod.py +0 -2
- odxtools/compumethods/limit.py +1 -1
- odxtools/compumethods/linearcompumethod.py +1 -1
- odxtools/compumethods/scalelinearcompumethod.py +0 -1
- odxtools/compumethods/tabintpcompumethod.py +0 -1
- odxtools/determinenumberofitems.py +18 -0
- odxtools/diagdatadictionaryspec.py +14 -4
- odxtools/diaglayer.py +54 -59
- odxtools/dynamiclengthfield.py +59 -0
- odxtools/element.py +2 -4
- odxtools/endofpdufield.py +6 -77
- odxtools/field.py +94 -0
- odxtools/isotp_state_machine.py +20 -24
- odxtools/matchingparameter.py +1 -1
- odxtools/multiplexer.py +6 -18
- odxtools/multiplexercase.py +22 -6
- odxtools/multiplexerdefaultcase.py +10 -2
- odxtools/multiplexerswitchkey.py +8 -43
- odxtools/odxlink.py +8 -4
- odxtools/odxtypes.py +1 -1
- odxtools/parameters/codedconstparameter.py +4 -2
- odxtools/parameters/dynamicparameter.py +6 -4
- odxtools/parameters/lengthkeyparameter.py +8 -3
- odxtools/parameters/matchingrequestparameter.py +5 -3
- odxtools/parameters/nrcconstparameter.py +4 -2
- odxtools/parameters/parameter.py +21 -6
- odxtools/parameters/parameterwithdop.py +6 -1
- odxtools/parameters/physicalconstantparameter.py +4 -2
- odxtools/parameters/reservedparameter.py +4 -2
- odxtools/parameters/systemparameter.py +5 -3
- odxtools/parameters/tableentryparameter.py +5 -3
- odxtools/parameters/tablekeyparameter.py +8 -4
- odxtools/parameters/tablestructparameter.py +4 -2
- odxtools/parameters/valueparameter.py +5 -3
- odxtools/positioneddataobjectproperty.py +74 -0
- odxtools/progcode.py +2 -3
- odxtools/tablerow.py +1 -2
- odxtools/templates/macros/printAudience.xml.jinja2 +3 -9
- odxtools/templates/macros/printCompanyData.xml.jinja2 +4 -27
- odxtools/templates/macros/printComparam.xml.jinja2 +4 -18
- odxtools/templates/macros/printDOP.xml.jinja2 +3 -9
- odxtools/templates/macros/printDynamicLengthField.xml.jinja2 +22 -0
- odxtools/templates/macros/printElementID.xml.jinja2 +6 -6
- odxtools/templates/macros/printEndOfPdu.xml.jinja2 +3 -2
- odxtools/templates/macros/printEnvData.xml.jinja2 +2 -2
- odxtools/templates/macros/printEnvDataDesc.xml.jinja2 +3 -2
- odxtools/templates/macros/printFunctionalClass.xml.jinja2 +3 -9
- odxtools/templates/macros/printMux.xml.jinja2 +13 -6
- odxtools/templates/macros/printParam.xml.jinja2 +2 -7
- odxtools/templates/macros/printRequest.xml.jinja2 +2 -9
- odxtools/templates/macros/printResponse.xml.jinja2 +2 -9
- odxtools/templates/macros/printService.xml.jinja2 +2 -9
- odxtools/templates/macros/printSpecialData.xml.jinja2 +1 -1
- odxtools/templates/macros/printState.xml.jinja2 +3 -9
- odxtools/templates/macros/printStateChart.xml.jinja2 +2 -9
- odxtools/templates/macros/printStateTransition.xml.jinja2 +3 -9
- odxtools/templates/macros/printStructure.xml.jinja2 +2 -4
- odxtools/templates/macros/printTable.xml.jinja2 +2 -7
- odxtools/templates/macros/printUnitSpec.xml.jinja2 +3 -3
- odxtools/templates/macros/printVariant.xml.jinja2 +10 -9
- odxtools/version.py +4 -2
- {odxtools-5.2.6.dist-info → odxtools-5.3.1.dist-info}/METADATA +70 -13
- {odxtools-5.2.6.dist-info → odxtools-5.3.1.dist-info}/RECORD +73 -68
- {odxtools-5.2.6.dist-info → odxtools-5.3.1.dist-info}/LICENSE +0 -0
- {odxtools-5.2.6.dist-info → odxtools-5.3.1.dist-info}/WHEEL +0 -0
- {odxtools-5.2.6.dist-info → odxtools-5.3.1.dist-info}/entry_points.txt +0 -0
- {odxtools-5.2.6.dist-info → odxtools-5.3.1.dist-info}/top_level.txt +0 -0
odxtools/basicstructure.py
CHANGED
@@ -77,7 +77,7 @@ class BasicStructure(DopBase):
|
|
77
77
|
def required_parameters(self) -> List[Parameter]:
|
78
78
|
"""Return the list of parameters which are required for
|
79
79
|
encoding the structure."""
|
80
|
-
return [p for p in self.parameters if p.is_required
|
80
|
+
return [p for p in self.parameters if p.is_required]
|
81
81
|
|
82
82
|
@property
|
83
83
|
def free_parameters(self) -> List[Union[Parameter, "EndOfPduField"]]: # type: ignore
|
@@ -96,7 +96,7 @@ class BasicStructure(DopBase):
|
|
96
96
|
if isinstance(param, EndOfPduField):
|
97
97
|
result.append(param)
|
98
98
|
continue
|
99
|
-
elif not param.is_required
|
99
|
+
elif not param.is_required:
|
100
100
|
continue
|
101
101
|
# The user cannot specify MatchingRequestParameters freely!
|
102
102
|
elif isinstance(param, MatchingRequestParameter):
|
odxtools/cli/browse.py
CHANGED
@@ -4,7 +4,7 @@ import logging
|
|
4
4
|
import sys
|
5
5
|
from typing import Dict, List, Union
|
6
6
|
|
7
|
-
import PyInquirer
|
7
|
+
import PyInquirer.prompt as PI_prompt
|
8
8
|
|
9
9
|
from ..database import Database
|
10
10
|
from ..diaglayer import DiagLayer
|
@@ -38,7 +38,7 @@ def _convert_string_to_bytes(string_value):
|
|
38
38
|
|
39
39
|
|
40
40
|
def _validate_string_value(input, parameter):
|
41
|
-
if parameter.is_optional
|
41
|
+
if parameter.is_optional and input == "":
|
42
42
|
return True
|
43
43
|
elif isinstance(parameter, ParameterWithDOP):
|
44
44
|
try:
|
@@ -62,7 +62,7 @@ def prompt_single_parameter_value(parameter):
|
|
62
62
|
parameter.short_name,
|
63
63
|
"message":
|
64
64
|
f"Value for parameter '{parameter.short_name}' (Type: {parameter.physical_type.base_data_type})"
|
65
|
-
+ (f"[optional]" if parameter.is_optional
|
65
|
+
+ (f"[optional]" if parameter.is_optional else ""),
|
66
66
|
# TODO: improve validation
|
67
67
|
"validate":
|
68
68
|
lambda x: _validate_string_value(x, parameter),
|
@@ -79,8 +79,8 @@ def prompt_single_parameter_value(parameter):
|
|
79
79
|
"message": f"Value for parameter '{parameter.short_name}'",
|
80
80
|
"choices": parameter.get_valid_physical_values(),
|
81
81
|
}]
|
82
|
-
answer =
|
83
|
-
if answer.get(parameter.short_name) == "" and parameter.is_optional
|
82
|
+
answer = PI_prompt.prompt(param_prompt)
|
83
|
+
if answer.get(parameter.short_name) == "" and parameter.is_optional:
|
84
84
|
return None
|
85
85
|
elif parameter.physical_type.base_data_type is not None:
|
86
86
|
return _convert_string_to_odx_type(
|
@@ -97,15 +97,13 @@ def encode_message_interactively(sub_service, ask_user_confirmation=False):
|
|
97
97
|
raise SystemError("This command can only be used in an interactive shell!")
|
98
98
|
param_dict = sub_service.parameter_dict()
|
99
99
|
|
100
|
-
# list(filter(lambda p: p.is_required()
|
101
|
-
# or p.is_optional(), sub_service.parameters))
|
102
100
|
exists_definable_param = False
|
103
101
|
for k, param_or_dict in param_dict.items():
|
104
102
|
if isinstance(param_or_dict, dict):
|
105
103
|
for k, param in param_or_dict.items():
|
106
|
-
if param.
|
104
|
+
if param.is_settable:
|
107
105
|
exists_definable_param = True
|
108
|
-
elif param_or_dict.
|
106
|
+
elif param_or_dict.is_settable:
|
109
107
|
exists_definable_param = True
|
110
108
|
|
111
109
|
param_values = {}
|
@@ -118,7 +116,7 @@ def encode_message_interactively(sub_service, ask_user_confirmation=False):
|
|
118
116
|
"message": f"Do you want to encode a message? [y/n]",
|
119
117
|
"choices": ["yes", "no"],
|
120
118
|
}]
|
121
|
-
answer =
|
119
|
+
answer = PI_prompt.prompt(encode_message_prompt)
|
122
120
|
if answer.get("yes_no_prompt") == "no":
|
123
121
|
return
|
124
122
|
|
@@ -133,7 +131,7 @@ def encode_message_interactively(sub_service, ask_user_confirmation=False):
|
|
133
131
|
"filter":
|
134
132
|
lambda input: _convert_string_to_bytes(input),
|
135
133
|
}]
|
136
|
-
answer =
|
134
|
+
answer = PI_prompt.prompt(answered_request_prompt)
|
137
135
|
answered_request = answer.get("request")
|
138
136
|
print(f"Input interpretation as list: {list(answered_request)}")
|
139
137
|
|
@@ -146,13 +144,12 @@ def encode_message_interactively(sub_service, ask_user_confirmation=False):
|
|
146
144
|
)
|
147
145
|
structure_param_values = {}
|
148
146
|
for param_sn, param in param_or_structure.items():
|
149
|
-
if param.
|
147
|
+
if param.is_settable:
|
150
148
|
val = prompt_single_parameter_value(param)
|
151
149
|
if val is not None:
|
152
150
|
structure_param_values[param_sn] = val
|
153
151
|
param_values[key] = structure_param_values
|
154
|
-
elif
|
155
|
-
) and param_or_structure.parameter_type != "MATCHING-REQUEST-PARAM":
|
152
|
+
elif param_or_structure.is_settable:
|
156
153
|
# param_or_structure is a parameter
|
157
154
|
val = prompt_single_parameter_value(param_or_structure)
|
158
155
|
if val is not None:
|
@@ -183,12 +180,13 @@ def encode_message_from_string_values(
|
|
183
180
|
structured_value = parameter_values.get(parameter_sn)
|
184
181
|
if not isinstance(simple_param, Parameter):
|
185
182
|
continue
|
186
|
-
if simple_param.is_required
|
187
|
-
|
183
|
+
if simple_param.is_required and (not isinstance(structured_value, dict) or
|
184
|
+
structured_value.get(simple_param_sn) is None):
|
188
185
|
missing_parameter_names.append(f"{parameter_sn} :: {simple_param_sn}")
|
189
186
|
else:
|
190
|
-
if parameter.is_required
|
187
|
+
if parameter.is_required and parameter_values.get(parameter_sn) is None:
|
191
188
|
missing_parameter_names.append(parameter_sn)
|
189
|
+
|
192
190
|
if len(missing_parameter_names) > 0:
|
193
191
|
print("The following parameters are required but missing!")
|
194
192
|
print(" - " + "\n - ".join(missing_parameter_names))
|
@@ -245,7 +243,7 @@ def browse(odxdb: Database):
|
|
245
243
|
"message": "Select a Variant.",
|
246
244
|
"choices": list(dl_names) + ["[exit]"],
|
247
245
|
}]
|
248
|
-
answer =
|
246
|
+
answer = PI_prompt.prompt(selection)
|
249
247
|
if answer.get("variant") == "[exit]":
|
250
248
|
return
|
251
249
|
|
@@ -281,7 +279,7 @@ def browse(odxdb: Database):
|
|
281
279
|
f"The variant {variant.short_name} offers the following services. Select one!",
|
282
280
|
"choices": [s.short_name for s in services] + ["[back]"],
|
283
281
|
}]
|
284
|
-
answer =
|
282
|
+
answer = PI_prompt.prompt(selection)
|
285
283
|
if answer.get("service") == "[back]":
|
286
284
|
break
|
287
285
|
|
@@ -315,7 +313,7 @@ def browse(odxdb: Database):
|
|
315
313
|
"short": f"Negative response: {nr.short_name}",
|
316
314
|
} for nr in service.negative_responses] + ["[back]"], # type: ignore
|
317
315
|
}]
|
318
|
-
answer =
|
316
|
+
answer = PI_prompt.prompt(selection)
|
319
317
|
if answer.get("message_type") == "[back]":
|
320
318
|
continue
|
321
319
|
|
odxtools/cli/dummy_sub_parser.py
CHANGED
@@ -14,11 +14,11 @@ class DummyTool:
|
|
14
14
|
should bail out.
|
15
15
|
"""
|
16
16
|
|
17
|
-
def __init__(self, tool_name, error):
|
17
|
+
def __init__(self, tool_name: str, error: Exception):
|
18
18
|
self._odxtools_tool_name_ = tool_name
|
19
19
|
self._error = error
|
20
20
|
|
21
|
-
def add_subparser(self, subparser_list):
|
21
|
+
def add_subparser(self, subparser_list: "argparse._SubParsersAction") -> None:
|
22
22
|
subparser_list.add_parser(
|
23
23
|
self._odxtools_tool_name_,
|
24
24
|
description=f"Tool '{self._odxtools_tool_name_}' is unavailable: {self._error}",
|
@@ -26,7 +26,7 @@ class DummyTool:
|
|
26
26
|
formatter_class=argparse.RawTextHelpFormatter,
|
27
27
|
)
|
28
28
|
|
29
|
-
def run(self, args: argparse.Namespace):
|
29
|
+
def run(self, args: argparse.Namespace) -> None:
|
30
30
|
print(
|
31
31
|
f"Error: Tool '{self._odxtools_tool_name_}' is unavailable: {self._error}",
|
32
32
|
file=sys.stderr,
|
odxtools/cli/main.py
CHANGED
@@ -16,7 +16,7 @@ for tool_name in ["list", "browse", "snoop", "find"]:
|
|
16
16
|
tool_modules.append(DummyTool(tool_name, e))
|
17
17
|
|
18
18
|
|
19
|
-
def start_cli():
|
19
|
+
def start_cli() -> None:
|
20
20
|
argparser = argparse.ArgumentParser(
|
21
21
|
description="\n".join([
|
22
22
|
"Utilities to interact with automotive diagnostic descriptions based on the ODX standard.",
|
@@ -1,9 +1,8 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import List,
|
3
|
+
from typing import List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
-
from ..exceptions import odxrequire
|
7
6
|
from ..odxlink import OdxDocFragment
|
8
7
|
from ..odxtypes import AtomicOdxType, DataType
|
9
8
|
from ..utils import create_description_from_et
|
@@ -7,7 +7,6 @@ from ..exceptions import OdxWarning, odxassert, odxraise, odxrequire
|
|
7
7
|
from ..globals import logger
|
8
8
|
from ..odxlink import OdxDocFragment
|
9
9
|
from ..odxtypes import DataType
|
10
|
-
from ..utils import create_description_from_et
|
11
10
|
from .compumethod import CompuMethod
|
12
11
|
from .compuscale import CompuScale
|
13
12
|
from .identicalcompumethod import IdenticalCompuMethod
|
odxtools/compumethods/limit.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from enum import Enum
|
4
|
-
from typing import
|
4
|
+
from typing import Optional, Union
|
5
5
|
from xml.etree import ElementTree
|
6
6
|
|
7
7
|
from ..exceptions import odxassert, odxraise, odxrequire
|
@@ -3,7 +3,6 @@ from dataclasses import dataclass
|
|
3
3
|
from typing import List, Tuple, Union
|
4
4
|
|
5
5
|
from ..exceptions import DecodeError, EncodeError, odxassert, odxraise
|
6
|
-
from ..globals import logger
|
7
6
|
from ..odxtypes import DataType
|
8
7
|
from .compumethod import CompuMethod, CompuMethodCategory
|
9
8
|
from .limit import IntervalType, Limit
|
@@ -0,0 +1,18 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import List
|
3
|
+
from xml.etree import ElementTree
|
4
|
+
|
5
|
+
from .odxlink import OdxDocFragment
|
6
|
+
from .positioneddataobjectproperty import PositionedDataObjectProperty
|
7
|
+
from .utils import dataclass_fields_asdict
|
8
|
+
|
9
|
+
|
10
|
+
@dataclass
|
11
|
+
class DetermineNumberOfItems(PositionedDataObjectProperty):
|
12
|
+
|
13
|
+
@staticmethod
|
14
|
+
def from_et(et_element: ElementTree.Element,
|
15
|
+
doc_frags: List[OdxDocFragment]) -> "DetermineNumberOfItems":
|
16
|
+
kwargs = dataclass_fields_asdict(
|
17
|
+
PositionedDataObjectProperty.from_et(et_element, doc_frags))
|
18
|
+
return DetermineNumberOfItems(**kwargs)
|
@@ -9,6 +9,7 @@ from .createanystructure import create_any_structure_from_et
|
|
9
9
|
from .createsdgs import create_sdgs_from_et
|
10
10
|
from .dataobjectproperty import DataObjectProperty
|
11
11
|
from .dtcdop import DtcDop
|
12
|
+
from .dynamiclengthfield import DynamicLengthField
|
12
13
|
from .endofpdufield import EndOfPduField
|
13
14
|
from .environmentdata import EnvironmentData
|
14
15
|
from .environmentdatadescription import EnvironmentDataDescription
|
@@ -31,6 +32,7 @@ class DiagDataDictionarySpec:
|
|
31
32
|
data_object_props: NamedItemList[DataObjectProperty]
|
32
33
|
structures: NamedItemList[BasicStructure]
|
33
34
|
end_of_pdu_fields: NamedItemList[EndOfPduField]
|
35
|
+
dynamic_length_fields: NamedItemList[DynamicLengthField]
|
34
36
|
tables: NamedItemList[Table]
|
35
37
|
env_data_descs: NamedItemList[EnvironmentDataDescription]
|
36
38
|
env_datas: NamedItemList[EnvironmentData]
|
@@ -44,6 +46,7 @@ class DiagDataDictionarySpec:
|
|
44
46
|
self.data_object_props,
|
45
47
|
self.structures,
|
46
48
|
self.end_of_pdu_fields,
|
49
|
+
self.dynamic_length_fields,
|
47
50
|
self.dtc_dops,
|
48
51
|
self.tables,
|
49
52
|
),)
|
@@ -67,6 +70,11 @@ class DiagDataDictionarySpec:
|
|
67
70
|
for eofp_element in et_element.iterfind("END-OF-PDU-FIELDS/END-OF-PDU-FIELD")
|
68
71
|
]
|
69
72
|
|
73
|
+
dynamic_length_fields = [
|
74
|
+
DynamicLengthField.from_et(dl_element, doc_frags)
|
75
|
+
for dl_element in et_element.iterfind("DYNAMIC-LENGTH-FIELDS/DYNAMIC-LENGTH-FIELD")
|
76
|
+
]
|
77
|
+
|
70
78
|
dtc_dops = []
|
71
79
|
for dtc_dop_elem in et_element.iterfind("DTC-DOPS/DTC-DOP"):
|
72
80
|
dtc_dop = DtcDop.from_et(dtc_dop_elem, doc_frags)
|
@@ -123,6 +131,7 @@ class DiagDataDictionarySpec:
|
|
123
131
|
data_object_props=NamedItemList(data_object_props),
|
124
132
|
structures=NamedItemList(structures),
|
125
133
|
end_of_pdu_fields=NamedItemList(end_of_pdu_fields),
|
134
|
+
dynamic_length_fields=NamedItemList(dynamic_length_fields),
|
126
135
|
dtc_dops=NamedItemList(dtc_dops),
|
127
136
|
unit_spec=unit_spec,
|
128
137
|
tables=NamedItemList(tables),
|
@@ -145,6 +154,7 @@ class DiagDataDictionarySpec:
|
|
145
154
|
self.sdgs,
|
146
155
|
self.structures,
|
147
156
|
self.end_of_pdu_fields,
|
157
|
+
self.dynamic_length_fields,
|
148
158
|
self.tables,
|
149
159
|
):
|
150
160
|
odxlinks.update(obj._build_odxlinks())
|
@@ -157,8 +167,8 @@ class DiagDataDictionarySpec:
|
|
157
167
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
158
168
|
|
159
169
|
for obj in chain(self.data_object_props, self.dtc_dops, self.end_of_pdu_fields,
|
160
|
-
self.
|
161
|
-
self.tables):
|
170
|
+
self.dynamic_length_fields, self.env_data_descs, self.env_datas, self.muxs,
|
171
|
+
self.sdgs, self.structures, self.tables):
|
162
172
|
obj._resolve_odxlinks(odxlinks)
|
163
173
|
|
164
174
|
if self.unit_spec is not None:
|
@@ -166,8 +176,8 @@ class DiagDataDictionarySpec:
|
|
166
176
|
|
167
177
|
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
168
178
|
for obj in chain(self.data_object_props, self.dtc_dops, self.end_of_pdu_fields,
|
169
|
-
self.
|
170
|
-
self.tables):
|
179
|
+
self.dynamic_length_fields, self.env_data_descs, self.env_datas, self.muxs,
|
180
|
+
self.sdgs, self.structures, self.tables):
|
171
181
|
obj._resolve_snrefs(diag_layer)
|
172
182
|
|
173
183
|
if self.unit_spec is not None:
|
odxtools/diaglayer.py
CHANGED
@@ -10,24 +10,17 @@ from deprecation import deprecated
|
|
10
10
|
|
11
11
|
from .additionalaudience import AdditionalAudience
|
12
12
|
from .admindata import AdminData
|
13
|
-
from .basicstructure import BasicStructure
|
14
13
|
from .communicationparameterref import CommunicationParameterRef
|
15
14
|
from .companydata import CompanyData
|
16
|
-
from .dataobjectproperty import DataObjectProperty
|
17
15
|
from .diagdatadictionaryspec import DiagDataDictionarySpec
|
18
16
|
from .diaglayerraw import DiagLayerRaw
|
19
17
|
from .diaglayertype import DiagLayerType
|
20
18
|
from .diagservice import DiagService
|
21
|
-
from .dtcdop import DtcDop
|
22
19
|
from .ecuvariantpattern import EcuVariantPattern
|
23
|
-
from .endofpdufield import EndOfPduField
|
24
|
-
from .environmentdata import EnvironmentData
|
25
|
-
from .environmentdatadescription import EnvironmentDataDescription
|
26
20
|
from .exceptions import DecodeError, OdxWarning, odxassert
|
27
21
|
from .functionalclass import FunctionalClass
|
28
22
|
from .message import Message
|
29
|
-
from .
|
30
|
-
from .nameditemlist import NamedItemList
|
23
|
+
from .nameditemlist import NamedItemList, OdxNamed
|
31
24
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
32
25
|
from .parentref import ParentRef
|
33
26
|
from .request import Request
|
@@ -40,6 +33,7 @@ from .unitgroup import UnitGroup
|
|
40
33
|
from .unitspec import UnitSpec
|
41
34
|
|
42
35
|
T = TypeVar("T")
|
36
|
+
TNamed = TypeVar("TNamed", bound=OdxNamed)
|
43
37
|
|
44
38
|
PrefixTree = Dict[int, Union[List[DiagService], "PrefixTree"]]
|
45
39
|
|
@@ -154,47 +148,58 @@ class DiagLayer:
|
|
154
148
|
sdgs=[])
|
155
149
|
############
|
156
150
|
|
157
|
-
dops =
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
151
|
+
dops = self._compute_available_ddd_spec_items(
|
152
|
+
lambda ddd_spec: ddd_spec.data_object_props,
|
153
|
+
lambda parent_ref: parent_ref.not_inherited_dops,
|
154
|
+
)
|
155
|
+
structures = self._compute_available_ddd_spec_items(
|
156
|
+
lambda ddd_spec: ddd_spec.structures,
|
157
|
+
lambda parent_ref: parent_ref.not_inherited_dops,
|
158
|
+
)
|
159
|
+
dtc_dops = self._compute_available_ddd_spec_items(
|
160
|
+
lambda ddd_spec: ddd_spec.dtc_dops,
|
161
|
+
lambda parent_ref: parent_ref.not_inherited_dops,
|
162
|
+
)
|
163
|
+
end_of_pdu_fields = self._compute_available_ddd_spec_items(
|
164
|
+
lambda ddd_spec: ddd_spec.end_of_pdu_fields,
|
165
|
+
lambda parent_ref: parent_ref.not_inherited_dops,
|
166
|
+
)
|
167
|
+
dynamic_length_fields = self._compute_available_ddd_spec_items(
|
168
|
+
lambda ddd_spec: ddd_spec.dynamic_length_fields,
|
169
|
+
lambda parent_ref: parent_ref.not_inherited_dops,
|
170
|
+
)
|
171
|
+
env_data_descs = self._compute_available_ddd_spec_items(
|
172
|
+
lambda ddd_spec: ddd_spec.env_data_descs,
|
173
|
+
lambda parent_ref: parent_ref.not_inherited_dops,
|
174
|
+
)
|
175
|
+
env_datas = self._compute_available_ddd_spec_items(
|
176
|
+
lambda ddd_spec: ddd_spec.env_datas, lambda parent_ref: parent_ref.not_inherited_dops)
|
177
|
+
muxs = self._compute_available_ddd_spec_items(
|
178
|
+
lambda ddd_spec: ddd_spec.muxs, lambda parent_ref: parent_ref.not_inherited_dops)
|
179
|
+
tables = self._compute_available_ddd_spec_items(
|
180
|
+
lambda ddd_spec: ddd_spec.tables, lambda parent_ref: parent_ref.not_inherited_tables)
|
165
181
|
ddds_sdgs: List[SpecialDataGroup]
|
166
182
|
if self.diag_layer_raw.diag_data_dictionary_spec:
|
167
|
-
dtc_dops = self.diag_layer_raw.diag_data_dictionary_spec.dtc_dops
|
168
|
-
structures = self.diag_layer_raw.diag_data_dictionary_spec.structures
|
169
|
-
end_of_pdu_fields = self.diag_layer_raw.diag_data_dictionary_spec.end_of_pdu_fields
|
170
|
-
env_data_descs = self.diag_layer_raw.diag_data_dictionary_spec.env_data_descs
|
171
|
-
env_datas = self.diag_layer_raw.diag_data_dictionary_spec.env_datas
|
172
|
-
muxs = self.diag_layer_raw.diag_data_dictionary_spec.muxs
|
173
183
|
ddds_sdgs = self.diag_layer_raw.diag_data_dictionary_spec.sdgs
|
174
184
|
else:
|
175
|
-
dtc_dops = NamedItemList()
|
176
|
-
structures = NamedItemList()
|
177
|
-
end_of_pdu_fields = NamedItemList()
|
178
|
-
env_data_descs = NamedItemList()
|
179
|
-
env_datas = NamedItemList()
|
180
|
-
muxs = NamedItemList()
|
181
185
|
ddds_sdgs = []
|
182
186
|
|
183
187
|
# create a DiagDataDictionarySpec which includes all the
|
184
188
|
# inherited objects. To me, this seems rather inelegant, but
|
185
189
|
# hey, it's described like this in the standard.
|
186
|
-
self._diag_data_dictionary_spec =
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
190
|
+
self._diag_data_dictionary_spec = DiagDataDictionarySpec(
|
191
|
+
data_object_props=dops,
|
192
|
+
dtc_dops=dtc_dops,
|
193
|
+
structures=structures,
|
194
|
+
end_of_pdu_fields=end_of_pdu_fields,
|
195
|
+
dynamic_length_fields=dynamic_length_fields,
|
196
|
+
tables=tables,
|
197
|
+
env_data_descs=env_data_descs,
|
198
|
+
env_datas=env_datas,
|
199
|
+
muxs=muxs,
|
200
|
+
unit_spec=unit_spec,
|
201
|
+
sdgs=ddds_sdgs,
|
202
|
+
)
|
198
203
|
|
199
204
|
#####
|
200
205
|
# compute the communication parameters applicable to the
|
@@ -457,29 +462,19 @@ class DiagLayer:
|
|
457
462
|
|
458
463
|
return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
|
459
464
|
|
460
|
-
def
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
return dl.diag_layer_raw.diag_data_dictionary_spec.data_object_props
|
466
|
-
|
467
|
-
def not_inherited_fn(parent_ref):
|
468
|
-
return parent_ref.not_inherited_dops
|
469
|
-
|
470
|
-
return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
|
471
|
-
|
472
|
-
def _compute_available_tables(self) -> Iterable[Table]:
|
465
|
+
def _compute_available_ddd_spec_items(
|
466
|
+
self,
|
467
|
+
include: Callable[[DiagDataDictionarySpec], Iterable[TNamed]],
|
468
|
+
exclude: Callable[["ParentRef"], List[str]],
|
469
|
+
) -> NamedItemList[TNamed]:
|
473
470
|
|
474
|
-
def get_local_objects_fn(dl):
|
471
|
+
def get_local_objects_fn(dl: "DiagLayer"):
|
475
472
|
if dl.diag_layer_raw.diag_data_dictionary_spec is None:
|
476
473
|
return []
|
477
|
-
return dl.diag_layer_raw.diag_data_dictionary_spec
|
474
|
+
return include(dl.diag_layer_raw.diag_data_dictionary_spec)
|
478
475
|
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
|
476
|
+
found = self._compute_available_objects(get_local_objects_fn, exclude)
|
477
|
+
return NamedItemList(found)
|
483
478
|
|
484
479
|
def _compute_available_functional_classes(self) -> Iterable[FunctionalClass]:
|
485
480
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import TYPE_CHECKING, Any, Dict, List
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from .decodestate import DecodeState
|
7
|
+
from .determinenumberofitems import DetermineNumberOfItems
|
8
|
+
from .encodestate import EncodeState
|
9
|
+
from .exceptions import odxrequire
|
10
|
+
from .field import Field
|
11
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
12
|
+
from .odxtypes import ParameterValueDict
|
13
|
+
from .utils import dataclass_fields_asdict
|
14
|
+
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
from .diaglayer import DiagLayer
|
17
|
+
|
18
|
+
|
19
|
+
@dataclass
|
20
|
+
class DynamicLengthField(Field):
|
21
|
+
"""Array of structure with length field"""
|
22
|
+
offset: int
|
23
|
+
determine_number_of_items: DetermineNumberOfItems
|
24
|
+
|
25
|
+
@staticmethod
|
26
|
+
def from_et(et_element: ElementTree.Element,
|
27
|
+
doc_frags: List[OdxDocFragment]) -> "DynamicLengthField":
|
28
|
+
kwargs = dataclass_fields_asdict(Field.from_et(et_element, doc_frags))
|
29
|
+
offset = int(odxrequire(et_element.findtext('OFFSET')))
|
30
|
+
determine_number_of_items = DetermineNumberOfItems.from_et(
|
31
|
+
odxrequire(et_element.find('DETERMINE-NUMBER-OF-ITEMS')),
|
32
|
+
doc_frags,
|
33
|
+
)
|
34
|
+
return DynamicLengthField(
|
35
|
+
offset=offset, determine_number_of_items=determine_number_of_items, **kwargs)
|
36
|
+
|
37
|
+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
38
|
+
odxlinks = super()._build_odxlinks()
|
39
|
+
odxlinks.update(self.determine_number_of_items._build_odxlinks())
|
40
|
+
return odxlinks
|
41
|
+
|
42
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
43
|
+
super()._resolve_odxlinks(odxlinks)
|
44
|
+
self.determine_number_of_items._resolve_odxlinks(odxlinks)
|
45
|
+
|
46
|
+
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
47
|
+
super()._resolve_snrefs(diag_layer)
|
48
|
+
self.determine_number_of_items._resolve_snrefs(diag_layer)
|
49
|
+
|
50
|
+
def convert_physical_to_bytes(
|
51
|
+
self,
|
52
|
+
physical_value: List[ParameterValueDict],
|
53
|
+
encode_state: EncodeState,
|
54
|
+
bit_position: int = 0,
|
55
|
+
) -> bytes:
|
56
|
+
raise NotImplementedError()
|
57
|
+
|
58
|
+
def convert_bytes_to_physical(self, decode_state: DecodeState, bit_position: int = 0):
|
59
|
+
raise NotImplementedError()
|
odxtools/element.py
CHANGED
@@ -2,11 +2,9 @@ from dataclasses import dataclass
|
|
2
2
|
from typing import List, Optional
|
3
3
|
from xml.etree import ElementTree
|
4
4
|
|
5
|
-
from
|
6
|
-
from odxtools.utils import create_description_from_et
|
7
|
-
|
5
|
+
from .exceptions import odxrequire
|
8
6
|
from .odxlink import OdxDocFragment, OdxLinkId
|
9
|
-
from .utils import dataclass_fields_asdict
|
7
|
+
from .utils import create_description_from_et, dataclass_fields_asdict
|
10
8
|
|
11
9
|
|
12
10
|
@dataclass
|