odxtools 9.5.0__py3-none-any.whl → 9.6.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/additionalaudience.py +2 -2
- odxtools/admindata.py +3 -0
- odxtools/audience.py +9 -13
- odxtools/basecomparam.py +1 -2
- odxtools/basevariantpattern.py +5 -5
- odxtools/basicstructure.py +34 -35
- odxtools/commrelation.py +2 -1
- odxtools/companydata.py +1 -2
- odxtools/companyspecificinfo.py +3 -0
- odxtools/comparam.py +16 -8
- odxtools/comparaminstance.py +12 -12
- odxtools/comparamspec.py +4 -3
- odxtools/comparamsubset.py +26 -24
- odxtools/compumethods/compuconst.py +4 -4
- odxtools/compumethods/limit.py +9 -9
- odxtools/compumethods/linearsegment.py +8 -8
- odxtools/dataobjectproperty.py +16 -18
- odxtools/description.py +4 -2
- odxtools/determinenumberofitems.py +4 -4
- odxtools/diagcodedtype.py +20 -20
- odxtools/diagcomm.py +61 -41
- odxtools/diagdatadictionaryspec.py +51 -55
- odxtools/diaglayercontainer.py +25 -25
- odxtools/diaglayers/diaglayerraw.py +26 -27
- odxtools/diagnostictroublecode.py +13 -10
- odxtools/diagservice.py +49 -51
- odxtools/diagvariable.py +10 -8
- odxtools/docrevision.py +5 -5
- odxtools/dtcdop.py +17 -17
- odxtools/dynamicendmarkerfield.py +8 -8
- odxtools/dynamiclengthfield.py +2 -0
- odxtools/dyndefinedspec.py +21 -8
- odxtools/encodestate.py +1 -2
- odxtools/endofpdufield.py +7 -9
- odxtools/environmentdatadescription.py +9 -20
- odxtools/field.py +21 -21
- odxtools/inputparam.py +15 -14
- odxtools/leadinglengthinfotype.py +4 -4
- odxtools/matchingparameter.py +2 -3
- odxtools/minmaxlengthtype.py +7 -7
- odxtools/multiplexer.py +38 -39
- odxtools/multiplexercase.py +3 -6
- odxtools/multiplexerdefaultcase.py +3 -6
- odxtools/multiplexerswitchkey.py +4 -4
- odxtools/negoutputparam.py +6 -9
- odxtools/odxlink.py +21 -5
- odxtools/odxtypes.py +4 -4
- odxtools/outputparam.py +9 -8
- odxtools/parameterinfo.py +1 -1
- odxtools/parameters/codedconstparameter.py +28 -27
- odxtools/parameters/dynamicparameter.py +9 -9
- odxtools/parameters/lengthkeyparameter.py +18 -18
- odxtools/parameters/matchingrequestparameter.py +15 -15
- odxtools/parameters/nrcconstparameter.py +32 -24
- odxtools/parameters/parameter.py +35 -37
- odxtools/parameters/parameterwithdop.py +6 -6
- odxtools/parameters/physicalconstantparameter.py +19 -20
- odxtools/parameters/reservedparameter.py +10 -11
- odxtools/parameters/systemparameter.py +10 -11
- odxtools/parameters/tableentryparameter.py +19 -20
- odxtools/parameters/tablekeyparameter.py +0 -2
- odxtools/parameters/tablestructparameter.py +27 -21
- odxtools/parameters/valueparameter.py +20 -20
- odxtools/parentref.py +6 -7
- odxtools/physicaldimension.py +11 -11
- odxtools/physicaltype.py +9 -14
- odxtools/preconditionstateref.py +85 -0
- odxtools/progcode.py +1 -2
- odxtools/protstack.py +4 -4
- odxtools/relateddoc.py +3 -4
- odxtools/scaleconstr.py +0 -1
- odxtools/singleecujob.py +8 -4
- odxtools/specialdata.py +10 -9
- odxtools/specialdatagroup.py +1 -0
- odxtools/standardlengthtype.py +10 -10
- odxtools/statechart.py +10 -6
- odxtools/statemachine.py +186 -0
- odxtools/statetransitionref.py +231 -0
- odxtools/structure.py +4 -4
- odxtools/subcomponent.py +72 -8
- odxtools/table.py +23 -13
- odxtools/tablerow.py +86 -69
- odxtools/teammember.py +4 -4
- odxtools/templates/macros/printCompanyData.xml.jinja2 +2 -2
- odxtools/templates/macros/printComparam.xml.jinja2 +3 -5
- odxtools/templates/macros/printDOP.xml.jinja2 +4 -1
- odxtools/templates/macros/printDiagComm.xml.jinja2 +6 -5
- odxtools/templates/macros/printParam.xml.jinja2 +5 -5
- odxtools/templates/macros/printPreConditionStateRef.xml.jinja2 +18 -0
- odxtools/templates/macros/printStateTransitionRef.xml.jinja2 +18 -0
- odxtools/templates/macros/printTable.xml.jinja2 +13 -9
- odxtools/text.py +35 -0
- odxtools/unit.py +1 -3
- odxtools/unitgroup.py +6 -8
- odxtools/utils.py +0 -4
- odxtools/version.py +2 -2
- {odxtools-9.5.0.dist-info → odxtools-9.6.1.dist-info}/METADATA +3 -2
- {odxtools-9.5.0.dist-info → odxtools-9.6.1.dist-info}/RECORD +102 -96
- {odxtools-9.5.0.dist-info → odxtools-9.6.1.dist-info}/WHEEL +1 -1
- {odxtools-9.5.0.dist-info → odxtools-9.6.1.dist-info}/entry_points.txt +0 -0
- {odxtools-9.5.0.dist-info → odxtools-9.6.1.dist-info/licenses}/LICENSE +0 -0
- {odxtools-9.5.0.dist-info → odxtools-9.6.1.dist-info}/top_level.txt +0 -0
odxtools/dyndefinedspec.py
CHANGED
@@ -4,7 +4,7 @@ from typing import Any, Dict, List, Optional, Union
|
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .diagcomm import DiagClassType, DiagComm
|
7
|
-
from .exceptions import odxraise, odxrequire
|
7
|
+
from .exceptions import odxassert, odxraise, odxrequire
|
8
8
|
from .nameditemlist import NamedItemList
|
9
9
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
10
10
|
from .snrefcontext import SnRefContext
|
@@ -50,17 +50,20 @@ class DynIdDefModeInfo:
|
|
50
50
|
|
51
51
|
clear_dyn_def_message_ref = OdxLinkRef.from_et(
|
52
52
|
et_element.find("CLEAR-DYN-DEF-MESSAGE-REF"), doc_frags)
|
53
|
+
clear_dyn_def_message_snref = None
|
53
54
|
if (snref_elem := et_element.find("CLEAR-DYN-DEF-MESSAGE-SNREF")) is not None:
|
54
|
-
clear_dyn_def_message_snref = snref_elem.attrib
|
55
|
+
clear_dyn_def_message_snref = odxrequire(snref_elem.attrib.get("SHORT-NAME"))
|
55
56
|
|
56
57
|
read_dyn_def_message_ref = OdxLinkRef.from_et(
|
57
58
|
et_element.find("READ-DYN-DEF-MESSAGE-REF"), doc_frags)
|
59
|
+
read_dyn_def_message_snref = None
|
58
60
|
if (snref_elem := et_element.find("READ-DYN-DEF-MESSAGE-SNREF")) is not None:
|
59
|
-
read_dyn_def_message_snref = snref_elem.attrib
|
61
|
+
read_dyn_def_message_snref = odxrequire(snref_elem.attrib.get("SHORT-NAME"))
|
60
62
|
|
61
63
|
dyn_def_message_ref = OdxLinkRef.from_et(et_element.find("DYN-DEF-MESSAGE-REF"), doc_frags)
|
64
|
+
dyn_def_message_snref = None
|
62
65
|
if (snref_elem := et_element.find("DYN-DEF-MESSAGE-SNREF")) is not None:
|
63
|
-
dyn_def_message_snref = snref_elem.attrib
|
66
|
+
dyn_def_message_snref = odxrequire(snref_elem.attrib.get("SHORT-NAME"))
|
64
67
|
|
65
68
|
supported_dyn_ids = [
|
66
69
|
bytes.fromhex(odxrequire(x.text))
|
@@ -89,14 +92,23 @@ class DynIdDefModeInfo:
|
|
89
92
|
selection_table_refs=selection_table_refs,
|
90
93
|
)
|
91
94
|
|
95
|
+
def __post_init__(self) -> None:
|
96
|
+
odxassert(
|
97
|
+
self.clear_dyn_def_message_ref is not None or
|
98
|
+
self.clear_dyn_def_message_snref is not None,
|
99
|
+
"A CLEAR-DYN-DEF-MESSAGE must be specified")
|
100
|
+
odxassert(
|
101
|
+
self.read_dyn_def_message_ref is not None or
|
102
|
+
self.read_dyn_def_message_snref is not None, "A READ-DYN-DEF-MESSAGE must be specified")
|
103
|
+
odxassert(self.dyn_def_message_ref is not None or self.dyn_def_message_snref is not None,
|
104
|
+
"A DYN-DEF-MESSAGE must be specified")
|
105
|
+
|
92
106
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
93
107
|
result: Dict[OdxLinkId, Any] = {}
|
94
108
|
|
95
109
|
return result
|
96
110
|
|
97
111
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
98
|
-
self._selection_tables = NamedItemList[Table]()
|
99
|
-
|
100
112
|
if self.clear_dyn_def_message_ref is not None:
|
101
113
|
self._clear_dyn_def_message = odxlinks.resolve(self.clear_dyn_def_message_ref, DiagComm)
|
102
114
|
|
@@ -106,7 +118,8 @@ class DynIdDefModeInfo:
|
|
106
118
|
if self.dyn_def_message_ref is not None:
|
107
119
|
self._dyn_def_message = odxlinks.resolve(self.dyn_def_message_ref, DiagComm)
|
108
120
|
|
109
|
-
# resolve the selection tables referenced
|
121
|
+
# resolve the selection tables that are referenced via ODXLINK
|
122
|
+
self._selection_tables = NamedItemList[Table]()
|
110
123
|
for x in self.selection_table_refs:
|
111
124
|
if isinstance(x, OdxLinkRef):
|
112
125
|
self._selection_tables.append(odxlinks.resolve(x, Table))
|
@@ -141,9 +154,9 @@ class DynIdDefModeInfo:
|
|
141
154
|
f"DYN-DEF-MESSAGE)")
|
142
155
|
|
143
156
|
# resolve the remaining selection tables that are referenced via SNREF
|
157
|
+
ddd_spec = odxrequire(diag_layer.diag_data_dictionary_spec)
|
144
158
|
for i, x in enumerate(self.selection_table_refs):
|
145
159
|
if isinstance(x, str):
|
146
|
-
ddd_spec = odxrequire(diag_layer.diag_data_dictionary_spec)
|
147
160
|
self._selection_tables.insert(i, resolve_snref(x, ddd_spec.tables, Table))
|
148
161
|
|
149
162
|
|
odxtools/encodestate.py
CHANGED
@@ -5,8 +5,7 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
|
|
5
5
|
|
6
6
|
from .encoding import Encoding, get_string_encoding
|
7
7
|
from .exceptions import EncodeError, OdxWarning, odxassert, odxraise
|
8
|
-
from .odxtypes import AtomicOdxType, DataType, ParameterValue
|
9
|
-
from .utils import BytesTypes
|
8
|
+
from .odxtypes import AtomicOdxType, BytesTypes, DataType, ParameterValue
|
10
9
|
|
11
10
|
try:
|
12
11
|
import bitstruct.c as bitstruct
|
odxtools/endofpdufield.py
CHANGED
@@ -17,30 +17,28 @@ from .utils import dataclass_fields_asdict
|
|
17
17
|
@dataclass
|
18
18
|
class EndOfPduField(Field):
|
19
19
|
"""End of PDU fields are structures that are repeated until the end of the PDU"""
|
20
|
-
min_number_of_items: Optional[int]
|
21
20
|
max_number_of_items: Optional[int]
|
21
|
+
min_number_of_items: Optional[int]
|
22
22
|
|
23
23
|
@staticmethod
|
24
24
|
def from_et(et_element: ElementTree.Element,
|
25
25
|
doc_frags: List[OdxDocFragment]) -> "EndOfPduField":
|
26
26
|
kwargs = dataclass_fields_asdict(Field.from_et(et_element, doc_frags))
|
27
27
|
|
28
|
-
if (min_n_str := et_element.findtext("MIN-NUMBER-OF-ITEMS")) is not None:
|
29
|
-
min_number_of_items = int(min_n_str)
|
30
|
-
else:
|
31
|
-
min_number_of_items = None
|
32
28
|
if (max_n_str := et_element.findtext("MAX-NUMBER-OF-ITEMS")) is not None:
|
33
29
|
max_number_of_items = int(max_n_str)
|
34
30
|
else:
|
35
31
|
max_number_of_items = None
|
32
|
+
if (min_n_str := et_element.findtext("MIN-NUMBER-OF-ITEMS")) is not None:
|
33
|
+
min_number_of_items = int(min_n_str)
|
34
|
+
else:
|
35
|
+
min_number_of_items = None
|
36
36
|
|
37
|
-
|
38
|
-
min_number_of_items=min_number_of_items,
|
37
|
+
return EndOfPduField(
|
39
38
|
max_number_of_items=max_number_of_items,
|
39
|
+
min_number_of_items=min_number_of_items,
|
40
40
|
**kwargs)
|
41
41
|
|
42
|
-
return eopf
|
43
|
-
|
44
42
|
@override
|
45
43
|
def encode_into_pdu(self, physical_value: Optional[ParameterValue],
|
46
44
|
encode_state: EncodeState) -> None:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import Any, Dict, List, Optional
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from typing_extensions import override
|
@@ -44,18 +44,6 @@ class EnvironmentDataDescription(ComplexDop):
|
|
44
44
|
env_datas: NamedItemList[EnvironmentData]
|
45
45
|
env_data_refs: List[OdxLinkRef]
|
46
46
|
|
47
|
-
@property
|
48
|
-
def param(self) -> Parameter:
|
49
|
-
# the parameter referenced via SNREF cannot be resolved here
|
50
|
-
# because the relevant list of parameters depends on the
|
51
|
-
# concrete codec object processed, whilst an environment data
|
52
|
-
# description object can be featured in an arbitrary number of
|
53
|
-
# responses. Instead, lookup of the appropriate parameter is
|
54
|
-
# done within the encode and decode methods.
|
55
|
-
odxraise("The parameter of ENV-DATA-DESC objects cannot be resolved "
|
56
|
-
"because it depends on the context")
|
57
|
-
return cast(None, Parameter)
|
58
|
-
|
59
47
|
@staticmethod
|
60
48
|
def from_et(et_element: ElementTree.Element,
|
61
49
|
doc_frags: List[OdxDocFragment]) -> "EnvironmentDataDescription":
|
@@ -74,20 +62,20 @@ class EnvironmentDataDescription(ComplexDop):
|
|
74
62
|
# situation is reversed. This means that we will create one
|
75
63
|
# empty and one non-empty list here. (Which is which depends
|
76
64
|
# on the version of the standard used by the file.)
|
77
|
-
env_data_refs = [
|
78
|
-
odxrequire(OdxLinkRef.from_et(env_data_ref, doc_frags))
|
79
|
-
for env_data_ref in et_element.iterfind("ENV-DATA-REFS/ENV-DATA-REF")
|
80
|
-
]
|
81
65
|
env_datas = NamedItemList([
|
82
66
|
EnvironmentData.from_et(env_data_elem, doc_frags)
|
83
67
|
for env_data_elem in et_element.iterfind("ENV-DATAS/ENV-DATA")
|
84
68
|
])
|
69
|
+
env_data_refs = [
|
70
|
+
odxrequire(OdxLinkRef.from_et(env_data_ref, doc_frags))
|
71
|
+
for env_data_ref in et_element.iterfind("ENV-DATA-REFS/ENV-DATA-REF")
|
72
|
+
]
|
85
73
|
|
86
74
|
return EnvironmentDataDescription(
|
87
75
|
param_snref=param_snref,
|
88
76
|
param_snpathref=param_snpathref,
|
89
|
-
env_data_refs=env_data_refs,
|
90
77
|
env_datas=env_datas,
|
78
|
+
env_data_refs=env_data_refs,
|
91
79
|
**kwargs)
|
92
80
|
|
93
81
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
@@ -103,7 +91,8 @@ class EnvironmentDataDescription(ComplexDop):
|
|
103
91
|
# ODX 2.0 specifies environment data objects here, ODX 2.2
|
104
92
|
# uses references
|
105
93
|
if self.env_data_refs:
|
106
|
-
self.env_datas = NamedItemList(
|
94
|
+
self.env_datas = NamedItemList(
|
95
|
+
[odxlinks.resolve(x, EnvironmentData) for x in self.env_data_refs])
|
107
96
|
else:
|
108
97
|
for ed in self.env_datas:
|
109
98
|
ed._resolve_odxlinks(odxlinks)
|
@@ -221,7 +210,7 @@ class EnvironmentDataDescription(ComplexDop):
|
|
221
210
|
if not isinstance(dop, (DataObjectProperty, DtcDop)):
|
222
211
|
odxraise(f"The DOP of the parameter referenced by environment data descriptions "
|
223
212
|
f"must use either be DataObjectProperty or a DtcDop (encountered "
|
224
|
-
f"{type(param).__name__} for parameter '{
|
213
|
+
f"{type(param).__name__} for parameter '{param.short_name}' "
|
225
214
|
f"of ENV-DATA-DESC '{self.short_name}')")
|
226
215
|
return 0
|
227
216
|
|
odxtools/field.py
CHANGED
@@ -21,19 +21,14 @@ class Field(ComplexDop):
|
|
21
21
|
env_data_desc_snref: Optional[str]
|
22
22
|
is_visible_raw: Optional[bool]
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
num_struct_refs += 0 if self.structure_snref is None else 1
|
29
|
-
|
30
|
-
num_edd_refs = 0 if self.env_data_desc_ref is None else 1
|
31
|
-
num_edd_refs += 0 if self.env_data_desc_snref is None else 1
|
24
|
+
@property
|
25
|
+
def structure(self) -> BasicStructure:
|
26
|
+
"""may be a Structure or a env-data-desc"""
|
27
|
+
return odxrequire(self._structure, "EnvironmentDataDescription is not supported")
|
32
28
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
"structure or an environment data description")
|
29
|
+
@property
|
30
|
+
def is_visible(self) -> bool:
|
31
|
+
return self.is_visible_raw in (None, True)
|
37
32
|
|
38
33
|
@staticmethod
|
39
34
|
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Field":
|
@@ -58,17 +53,19 @@ class Field(ComplexDop):
|
|
58
53
|
is_visible_raw=is_visible_raw,
|
59
54
|
**kwargs)
|
60
55
|
|
61
|
-
|
62
|
-
|
63
|
-
|
56
|
+
def __post_init__(self) -> None:
|
57
|
+
self._structure: Optional[BasicStructure] = None
|
58
|
+
self._env_data_desc: Optional[EnvironmentDataDescription] = None
|
59
|
+
num_struct_refs = 0 if self.structure_ref is None else 1
|
60
|
+
num_struct_refs += 0 if self.structure_snref is None else 1
|
64
61
|
|
65
|
-
|
66
|
-
|
67
|
-
"""may be a Structure or a env-data-desc"""
|
68
|
-
return odxrequire(self._structure, "EnvironmentDataDescription is not supported")
|
62
|
+
num_edd_refs = 0 if self.env_data_desc_ref is None else 1
|
63
|
+
num_edd_refs += 0 if self.env_data_desc_snref is None else 1
|
69
64
|
|
70
|
-
|
71
|
-
|
65
|
+
odxassert(
|
66
|
+
num_struct_refs + num_edd_refs == 1,
|
67
|
+
"FIELDs need to specify exactly one reference to a "
|
68
|
+
"structure or an environment data description")
|
72
69
|
|
73
70
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
74
71
|
"""Recursively resolve any odxlinks references"""
|
@@ -89,3 +86,6 @@ class Field(ComplexDop):
|
|
89
86
|
if self.env_data_desc_snref is not None:
|
90
87
|
self._env_data_desc = resolve_snref(self.env_data_desc_snref, ddds.env_data_descs,
|
91
88
|
EnvironmentDataDescription)
|
89
|
+
|
90
|
+
def get_static_bit_length(self) -> Optional[int]:
|
91
|
+
return None
|
odxtools/inputparam.py
CHANGED
@@ -15,25 +15,35 @@ from .utils import dataclass_fields_asdict
|
|
15
15
|
|
16
16
|
@dataclass
|
17
17
|
class InputParam(NamedElement):
|
18
|
+
physical_default_value: Optional[str]
|
18
19
|
dop_base_ref: OdxLinkRef
|
19
20
|
oid: Optional[str]
|
20
21
|
semantic: Optional[str]
|
21
|
-
|
22
|
+
|
23
|
+
@property
|
24
|
+
def dop(self) -> DopBase:
|
25
|
+
"""The data object property describing this parameter."""
|
26
|
+
return self._dop
|
27
|
+
|
28
|
+
@deprecated(details="use .dop") # type: ignore[misc]
|
29
|
+
def dop_base(self) -> DopBase:
|
30
|
+
return self._dop
|
22
31
|
|
23
32
|
@staticmethod
|
24
33
|
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "InputParam":
|
25
34
|
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
|
26
|
-
|
35
|
+
|
27
36
|
physical_default_value = et_element.findtext("PHYSICAL-DEFAULT-VALUE")
|
37
|
+
dop_base_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DOP-BASE-REF"), doc_frags))
|
28
38
|
|
29
|
-
semantic = et_element.get("SEMANTIC")
|
30
39
|
oid = et_element.get("OID")
|
40
|
+
semantic = et_element.get("SEMANTIC")
|
31
41
|
|
32
42
|
return InputParam(
|
33
|
-
dop_base_ref=dop_base_ref,
|
34
43
|
physical_default_value=physical_default_value,
|
35
|
-
|
44
|
+
dop_base_ref=dop_base_ref,
|
36
45
|
oid=oid,
|
46
|
+
semantic=semantic,
|
37
47
|
**kwargs)
|
38
48
|
|
39
49
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
@@ -44,12 +54,3 @@ class InputParam(NamedElement):
|
|
44
54
|
|
45
55
|
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
46
56
|
pass
|
47
|
-
|
48
|
-
@property
|
49
|
-
def dop(self) -> DopBase:
|
50
|
-
"""The data object property describing this parameter."""
|
51
|
-
return self._dop
|
52
|
-
|
53
|
-
@deprecated(details="use .dop") # type: ignore[misc]
|
54
|
-
def dop_base(self) -> DopBase:
|
55
|
-
return self._dop
|
@@ -23,6 +23,10 @@ class LeadingLengthInfoType(DiagCodedType):
|
|
23
23
|
#: object.
|
24
24
|
bit_length: int
|
25
25
|
|
26
|
+
@property
|
27
|
+
def dct_type(self) -> DctType:
|
28
|
+
return "LEADING-LENGTH-INFO-TYPE"
|
29
|
+
|
26
30
|
@staticmethod
|
27
31
|
@override
|
28
32
|
def from_et(et_element: ElementTree.Element,
|
@@ -46,10 +50,6 @@ class LeadingLengthInfoType(DiagCodedType):
|
|
46
50
|
f"A leading length info type cannot have the base data type {self.base_data_type.name}."
|
47
51
|
)
|
48
52
|
|
49
|
-
@property
|
50
|
-
def dct_type(self) -> DctType:
|
51
|
-
return "LEADING-LENGTH-INFO-TYPE"
|
52
|
-
|
53
53
|
@override
|
54
54
|
def encode_into_pdu(self, internal_value: AtomicOdxType, encode_state: EncodeState) -> None:
|
55
55
|
|
odxtools/matchingparameter.py
CHANGED
@@ -8,9 +8,8 @@ from .diagnostictroublecode import DiagnosticTroubleCode
|
|
8
8
|
from .diagservice import DiagService
|
9
9
|
from .exceptions import odxraise, odxrequire
|
10
10
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, resolve_snref
|
11
|
-
from .odxtypes import ParameterValue, ParameterValueDict
|
11
|
+
from .odxtypes import BytesTypes, ParameterValue, ParameterValueDict
|
12
12
|
from .snrefcontext import SnRefContext
|
13
|
-
from .utils import BytesTypes
|
14
13
|
|
15
14
|
|
16
15
|
@dataclass
|
@@ -53,7 +52,7 @@ class MatchingParameter:
|
|
53
52
|
elif (out_param_snpathref_el := et_element.find("OUT-PARAM-IF-SNPATHREF")) is not None:
|
54
53
|
out_param_if_snpathref = odxrequire(out_param_snpathref_el.get("SHORT-NAME-PATH"))
|
55
54
|
else:
|
56
|
-
odxraise("Output parameter must not left unspecified")
|
55
|
+
odxraise("Output parameter must not be left unspecified")
|
57
56
|
|
58
57
|
return MatchingParameter(
|
59
58
|
expected_value=expected_value,
|
odxtools/minmaxlengthtype.py
CHANGED
@@ -10,10 +10,10 @@ from .decodestate import DecodeState
|
|
10
10
|
from .diagcodedtype import DctType, DiagCodedType
|
11
11
|
from .encodestate import EncodeState
|
12
12
|
from .encoding import get_string_encoding
|
13
|
-
from .exceptions import
|
13
|
+
from .exceptions import DecodeError, EncodeError, odxassert, odxraise, odxrequire
|
14
14
|
from .odxlink import OdxDocFragment
|
15
|
-
from .odxtypes import AtomicOdxType, DataType
|
16
|
-
from .utils import
|
15
|
+
from .odxtypes import AtomicOdxType, BytesTypes, DataType
|
16
|
+
from .utils import dataclass_fields_asdict
|
17
17
|
|
18
18
|
|
19
19
|
class Termination(Enum):
|
@@ -24,8 +24,8 @@ class Termination(Enum):
|
|
24
24
|
|
25
25
|
@dataclass
|
26
26
|
class MinMaxLengthType(DiagCodedType):
|
27
|
-
min_length: int
|
28
27
|
max_length: Optional[int]
|
28
|
+
min_length: int
|
29
29
|
termination: Termination
|
30
30
|
|
31
31
|
@property
|
@@ -38,12 +38,12 @@ class MinMaxLengthType(DiagCodedType):
|
|
38
38
|
doc_frags: List[OdxDocFragment]) -> "MinMaxLengthType":
|
39
39
|
kwargs = dataclass_fields_asdict(DiagCodedType.from_et(et_element, doc_frags))
|
40
40
|
|
41
|
-
min_length = int(odxrequire(et_element.findtext("MIN-LENGTH")))
|
42
41
|
max_length = None
|
43
42
|
if et_element.find("MAX-LENGTH") is not None:
|
44
43
|
max_length = int(odxrequire(et_element.findtext("MAX-LENGTH")))
|
44
|
+
min_length = int(odxrequire(et_element.findtext("MIN-LENGTH")))
|
45
45
|
|
46
|
-
termination_str = odxrequire(et_element.get("TERMINATION"))
|
46
|
+
termination_str = odxrequire(et_element.attrib.get("TERMINATION"))
|
47
47
|
try:
|
48
48
|
termination = Termination(termination_str)
|
49
49
|
except ValueError:
|
@@ -51,7 +51,7 @@ class MinMaxLengthType(DiagCodedType):
|
|
51
51
|
odxraise(f"Encountered unknown termination type '{termination_str}'")
|
52
52
|
|
53
53
|
return MinMaxLengthType(
|
54
|
-
|
54
|
+
max_length=max_length, min_length=min_length, termination=termination, **kwargs)
|
55
55
|
|
56
56
|
def __post_init__(self) -> None:
|
57
57
|
odxassert(self.max_length is None or self.min_length <= self.max_length)
|
odxtools/multiplexer.py
CHANGED
@@ -34,12 +34,15 @@ class Multiplexer(ComplexDop):
|
|
34
34
|
cases: NamedItemList[MultiplexerCase]
|
35
35
|
is_visible_raw: Optional[bool]
|
36
36
|
|
37
|
+
@property
|
38
|
+
def is_visible(self) -> bool:
|
39
|
+
return self.is_visible_raw is True
|
40
|
+
|
37
41
|
@staticmethod
|
38
42
|
@override
|
39
43
|
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Multiplexer":
|
40
44
|
"""Reads a Multiplexer from Diag Layer."""
|
41
|
-
|
42
|
-
kwargs = dataclass_fields_asdict(base_obj)
|
45
|
+
kwargs = dataclass_fields_asdict(ComplexDop.from_et(et_element, doc_frags))
|
43
46
|
|
44
47
|
byte_position = int(et_element.findtext("BYTE-POSITION", "0"))
|
45
48
|
switch_key = MultiplexerSwitchKey.from_et(
|
@@ -55,16 +58,45 @@ class Multiplexer(ComplexDop):
|
|
55
58
|
is_visible_raw = odxstr_to_bool(et_element.get("IS-VISIBLE"))
|
56
59
|
|
57
60
|
return Multiplexer(
|
58
|
-
is_visible_raw=is_visible_raw,
|
59
61
|
byte_position=byte_position,
|
60
62
|
switch_key=switch_key,
|
61
63
|
default_case=default_case,
|
62
64
|
cases=cases,
|
65
|
+
is_visible_raw=is_visible_raw,
|
63
66
|
**kwargs)
|
64
67
|
|
65
|
-
@
|
66
|
-
def
|
67
|
-
|
68
|
+
@override
|
69
|
+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
70
|
+
odxlinks = super()._build_odxlinks()
|
71
|
+
|
72
|
+
odxlinks.update(self.switch_key._build_odxlinks())
|
73
|
+
if self.default_case is not None:
|
74
|
+
odxlinks.update(self.default_case._build_odxlinks())
|
75
|
+
|
76
|
+
return odxlinks
|
77
|
+
|
78
|
+
@override
|
79
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
80
|
+
super()._resolve_odxlinks(odxlinks)
|
81
|
+
|
82
|
+
self.switch_key._resolve_odxlinks(odxlinks)
|
83
|
+
if self.default_case is not None:
|
84
|
+
self.default_case._resolve_odxlinks(odxlinks)
|
85
|
+
|
86
|
+
for mux_case in self.cases:
|
87
|
+
mux_case._mux_case_resolve_odxlinks(
|
88
|
+
odxlinks, key_physical_type=self.switch_key.dop.physical_type.base_data_type)
|
89
|
+
|
90
|
+
@override
|
91
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
92
|
+
super()._resolve_snrefs(context)
|
93
|
+
|
94
|
+
self.switch_key._resolve_snrefs(context)
|
95
|
+
if self.default_case is not None:
|
96
|
+
self.default_case._resolve_snrefs(context)
|
97
|
+
|
98
|
+
for mux_case in self.cases:
|
99
|
+
mux_case._resolve_snrefs(context)
|
68
100
|
|
69
101
|
def _get_case_limits(self, case: MultiplexerCase) -> Tuple[AtomicOdxType, AtomicOdxType]:
|
70
102
|
key_type = self.switch_key.dop.physical_type.base_data_type
|
@@ -203,36 +235,3 @@ class Multiplexer(ComplexDop):
|
|
203
235
|
decode_state.origin_byte_position = orig_origin
|
204
236
|
|
205
237
|
return result
|
206
|
-
|
207
|
-
@override
|
208
|
-
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
209
|
-
odxlinks = super()._build_odxlinks()
|
210
|
-
|
211
|
-
odxlinks.update(self.switch_key._build_odxlinks())
|
212
|
-
if self.default_case is not None:
|
213
|
-
odxlinks.update(self.default_case._build_odxlinks())
|
214
|
-
|
215
|
-
return odxlinks
|
216
|
-
|
217
|
-
@override
|
218
|
-
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
219
|
-
super()._resolve_odxlinks(odxlinks)
|
220
|
-
|
221
|
-
self.switch_key._resolve_odxlinks(odxlinks)
|
222
|
-
if self.default_case is not None:
|
223
|
-
self.default_case._resolve_odxlinks(odxlinks)
|
224
|
-
|
225
|
-
for mux_case in self.cases:
|
226
|
-
mux_case._mux_case_resolve_odxlinks(
|
227
|
-
odxlinks, key_physical_type=self.switch_key.dop.physical_type.base_data_type)
|
228
|
-
|
229
|
-
@override
|
230
|
-
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
231
|
-
super()._resolve_snrefs(context)
|
232
|
-
|
233
|
-
self.switch_key._resolve_snrefs(context)
|
234
|
-
if self.default_case is not None:
|
235
|
-
self.default_case._resolve_snrefs(context)
|
236
|
-
|
237
|
-
for mux_case in self.cases:
|
238
|
-
mux_case._resolve_snrefs(context)
|
odxtools/multiplexercase.py
CHANGED
@@ -22,8 +22,9 @@ class MultiplexerCase(NamedElement):
|
|
22
22
|
lower_limit: Limit
|
23
23
|
upper_limit: Limit
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
@property
|
26
|
+
def structure(self) -> Optional[Structure]:
|
27
|
+
return self._structure
|
27
28
|
|
28
29
|
@staticmethod
|
29
30
|
def from_et(et_element: ElementTree.Element,
|
@@ -77,7 +78,3 @@ class MultiplexerCase(NamedElement):
|
|
77
78
|
def applies(self, value: AtomicOdxType) -> bool:
|
78
79
|
return self.lower_limit.complies_to_lower(value) \
|
79
80
|
and self.upper_limit.complies_to_upper(value)
|
80
|
-
|
81
|
-
@property
|
82
|
-
def structure(self) -> Optional[Structure]:
|
83
|
-
return self._structure
|
@@ -17,8 +17,9 @@ class MultiplexerDefaultCase(NamedElement):
|
|
17
17
|
structure_ref: Optional[OdxLinkRef]
|
18
18
|
structure_snref: Optional[str]
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
@property
|
21
|
+
def structure(self) -> Optional[Structure]:
|
22
|
+
return self._structure
|
22
23
|
|
23
24
|
@staticmethod
|
24
25
|
def from_et(et_element: ElementTree.Element,
|
@@ -46,7 +47,3 @@ class MultiplexerDefaultCase(NamedElement):
|
|
46
47
|
if self.structure_snref:
|
47
48
|
ddds = odxrequire(context.diag_layer).diag_data_dictionary_spec
|
48
49
|
self._structure = resolve_snref(self.structure_snref, ddds.structures, Structure)
|
49
|
-
|
50
|
-
@property
|
51
|
-
def structure(self) -> Optional[Structure]:
|
52
|
-
return self._structure
|
odxtools/multiplexerswitchkey.py
CHANGED
@@ -18,6 +18,10 @@ class MultiplexerSwitchKey:
|
|
18
18
|
bit_position: Optional[int]
|
19
19
|
dop_ref: OdxLinkRef
|
20
20
|
|
21
|
+
@property
|
22
|
+
def dop(self) -> DataObjectProperty:
|
23
|
+
return self._dop
|
24
|
+
|
21
25
|
@staticmethod
|
22
26
|
def from_et(et_element: ElementTree.Element,
|
23
27
|
doc_frags: List[OdxDocFragment]) -> "MultiplexerSwitchKey":
|
@@ -40,7 +44,3 @@ class MultiplexerSwitchKey:
|
|
40
44
|
|
41
45
|
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
42
46
|
pass
|
43
|
-
|
44
|
-
@property
|
45
|
-
def dop(self) -> DataObjectProperty:
|
46
|
-
return self._dop
|
odxtools/negoutputparam.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import Any, Dict, List
|
3
|
+
from typing import Any, Dict, List
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .dopbase import DopBase
|
@@ -15,8 +15,10 @@ from .utils import dataclass_fields_asdict
|
|
15
15
|
class NegOutputParam(NamedElement):
|
16
16
|
dop_base_ref: OdxLinkRef
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
@property
|
19
|
+
def dop(self) -> DopBase:
|
20
|
+
"""The data object property describing this parameter."""
|
21
|
+
return self._dop
|
20
22
|
|
21
23
|
@staticmethod
|
22
24
|
def from_et(et_element: ElementTree.Element,
|
@@ -31,12 +33,7 @@ class NegOutputParam(NamedElement):
|
|
31
33
|
return {}
|
32
34
|
|
33
35
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
34
|
-
self._dop = odxlinks.resolve(self.dop_base_ref)
|
36
|
+
self._dop = odxlinks.resolve(self.dop_base_ref, DopBase)
|
35
37
|
|
36
38
|
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
37
39
|
pass
|
38
|
-
|
39
|
-
@property
|
40
|
-
def dop(self) -> Optional[DopBase]:
|
41
|
-
"""The data object property describing this parameter."""
|
42
|
-
return self._dop
|
odxtools/odxlink.py
CHANGED
@@ -277,24 +277,40 @@ class OdxLinkDatabase:
|
|
277
277
|
@overload
|
278
278
|
def resolve_snref(target_short_name: str,
|
279
279
|
items: Iterable[OdxNamed],
|
280
|
-
expected_type: None = None
|
280
|
+
expected_type: None = None,
|
281
|
+
*,
|
282
|
+
lenient: None = None) -> Any:
|
281
283
|
"""Resolve a short name reference given a sequence of candidate objects"""
|
282
284
|
...
|
283
285
|
|
284
286
|
|
285
287
|
@overload
|
286
|
-
def resolve_snref(target_short_name: str,
|
287
|
-
|
288
|
+
def resolve_snref(target_short_name: str,
|
289
|
+
items: Iterable[OdxNamed],
|
290
|
+
expected_type: Type[TNamed],
|
291
|
+
*,
|
292
|
+
lenient: None = None) -> TNamed:
|
293
|
+
...
|
294
|
+
|
295
|
+
|
296
|
+
@overload
|
297
|
+
def resolve_snref(target_short_name: str,
|
298
|
+
items: Iterable[OdxNamed],
|
299
|
+
expected_type: Type[TNamed],
|
300
|
+
*,
|
301
|
+
lenient: bool = True) -> Optional[TNamed]:
|
288
302
|
...
|
289
303
|
|
290
304
|
|
291
305
|
def resolve_snref(target_short_name: str,
|
292
306
|
items: Iterable[OdxNamed],
|
293
|
-
expected_type: Any = None
|
307
|
+
expected_type: Any = None,
|
308
|
+
lenient: Optional[bool] = None) -> Any:
|
294
309
|
candidates = [x for x in items if x.short_name == target_short_name]
|
295
310
|
|
296
311
|
if not candidates:
|
297
|
-
|
312
|
+
if not lenient:
|
313
|
+
odxraise(f"Cannot resolve short name reference to '{target_short_name}'")
|
298
314
|
return None
|
299
315
|
elif len(candidates) > 1:
|
300
316
|
odxraise(f"Cannot uniquely resolve short name reference to '{target_short_name}'")
|