odxtools 9.4.1__py3-none-any.whl → 9.6.0__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 +38 -0
- 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/basevariant.py +5 -0
- odxtools/diaglayers/basevariantraw.py +7 -1
- odxtools/diaglayers/diaglayerraw.py +26 -27
- odxtools/diaglayers/ecuvariant.py +16 -0
- odxtools/diagnostictroublecode.py +13 -10
- odxtools/diagservice.py +48 -50
- 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/ecuvariantpattern.py +20 -9
- odxtools/encodestate.py +3 -3
- 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/matchingbasevariantparameter.py +38 -0
- odxtools/matchingparameter.py +108 -28
- odxtools/minmaxlengthtype.py +6 -6
- 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 +7 -6
- 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 +18 -18
- odxtools/statechart.py +10 -6
- odxtools/statemachine.py +186 -0
- odxtools/statetransitionref.py +231 -0
- odxtools/structure.py +4 -4
- odxtools/subcomponent.py +78 -11
- odxtools/table.py +23 -13
- odxtools/tablerow.py +86 -69
- odxtools/teammember.py +4 -4
- odxtools/templates/macros/printBaseVariant.xml.jinja2 +4 -9
- odxtools/templates/macros/printBaseVariantPattern.xml.jinja2 +32 -0
- 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/printEcuVariantPattern.xml.jinja2 +7 -6
- 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/variantmatcher.py +209 -0
- odxtools/variantpattern.py +38 -0
- odxtools/version.py +2 -2
- {odxtools-9.4.1.dist-info → odxtools-9.6.0.dist-info}/METADATA +3 -2
- {odxtools-9.4.1.dist-info → odxtools-9.6.0.dist-info}/RECORD +111 -102
- {odxtools-9.4.1.dist-info → odxtools-9.6.0.dist-info}/WHEEL +1 -1
- odxtools/createecuvariantpatterns.py +0 -18
- odxtools/ecuvariantmatcher.py +0 -171
- {odxtools-9.4.1.dist-info → odxtools-9.6.0.dist-info}/entry_points.txt +0 -0
- {odxtools-9.4.1.dist-info → odxtools-9.6.0.dist-info/licenses}/LICENSE +0 -0
- {odxtools-9.4.1.dist-info → odxtools-9.6.0.dist-info}/top_level.txt +0 -0
odxtools/minmaxlengthtype.py
CHANGED
@@ -12,7 +12,7 @@ from .encodestate import EncodeState
|
|
12
12
|
from .encoding import get_string_encoding
|
13
13
|
from .exceptions import DecodeError, EncodeError, odxassert, odxraise, odxrequire
|
14
14
|
from .odxlink import OdxDocFragment
|
15
|
-
from .odxtypes import AtomicOdxType, DataType
|
15
|
+
from .odxtypes import AtomicOdxType, BytesTypes, DataType
|
16
16
|
from .utils import dataclass_fields_asdict
|
17
17
|
|
18
18
|
|
@@ -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)
|
@@ -83,7 +83,7 @@ class MinMaxLengthType(DiagCodedType):
|
|
83
83
|
@override
|
84
84
|
def encode_into_pdu(self, internal_value: AtomicOdxType, encode_state: EncodeState) -> None:
|
85
85
|
|
86
|
-
if not isinstance(internal_value, (
|
86
|
+
if not isinstance(internal_value, (str, BytesTypes)):
|
87
87
|
odxraise("MinMaxLengthType is currently only implemented for strings and byte arrays",
|
88
88
|
EncodeError)
|
89
89
|
|
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}'")
|
odxtools/odxtypes.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from enum import Enum
|
3
|
-
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, Optional,
|
4
|
-
overload)
|
3
|
+
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, Optional, SupportsBytes, Tuple,
|
4
|
+
Type, Union, overload)
|
5
5
|
from xml.etree import ElementTree
|
6
6
|
|
7
7
|
from .exceptions import odxassert, odxraise, odxrequire
|
@@ -16,7 +16,8 @@ def bytefield_to_bytearray(bytefield: str) -> bytearray:
|
|
16
16
|
return bytearray([int(x, 16) for x in bytes_string])
|
17
17
|
|
18
18
|
|
19
|
-
|
19
|
+
BytesTypes = (bytearray, bytes, SupportsBytes)
|
20
|
+
AtomicOdxType = Union[str, int, float, bytearray, bytes]
|
20
21
|
|
21
22
|
# dictionary mapping short names to a Parameter that needs to be
|
22
23
|
# specified. Complex parameters (structures) may contain
|
@@ -135,8 +136,8 @@ def compare_odx_values(a: AtomicOdxType, b: AtomicOdxType) -> int:
|
|
135
136
|
|
136
137
|
# bytefields are treated like long integers: to pad the shorter
|
137
138
|
# object with zeros and treat the results like strings.
|
138
|
-
if isinstance(a,
|
139
|
-
if not isinstance(b,
|
139
|
+
if isinstance(a, BytesTypes):
|
140
|
+
if not isinstance(b, BytesTypes):
|
140
141
|
odxraise()
|
141
142
|
|
142
143
|
obj_len = max(len(a), len(b))
|
@@ -237,7 +238,7 @@ class DataType(Enum):
|
|
237
238
|
return True
|
238
239
|
elif expected_type is float and isinstance(value, (int, float)):
|
239
240
|
return True
|
240
|
-
elif self == DataType.A_BYTEFIELD and isinstance(value,
|
241
|
+
elif self == DataType.A_BYTEFIELD and isinstance(value, BytesTypes):
|
241
242
|
return True
|
242
243
|
else:
|
243
244
|
return False
|
odxtools/outputparam.py
CHANGED
@@ -18,10 +18,19 @@ class OutputParam(IdentifiableElement):
|
|
18
18
|
dop_base_ref: OdxLinkRef
|
19
19
|
semantic: Optional[str]
|
20
20
|
|
21
|
+
@property
|
22
|
+
def dop(self) -> DopBase:
|
23
|
+
return self._dop
|
24
|
+
|
25
|
+
@deprecated(details="use .dop") # type: ignore[misc]
|
26
|
+
def dop_base(self) -> DopBase:
|
27
|
+
return self._dop
|
28
|
+
|
21
29
|
@staticmethod
|
22
30
|
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "OutputParam":
|
23
31
|
|
24
32
|
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
33
|
+
|
25
34
|
dop_base_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DOP-BASE-REF"), doc_frags))
|
26
35
|
semantic = et_element.get("SEMANTIC")
|
27
36
|
|
@@ -35,11 +44,3 @@ class OutputParam(IdentifiableElement):
|
|
35
44
|
|
36
45
|
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
37
46
|
pass
|
38
|
-
|
39
|
-
@property
|
40
|
-
def dop(self) -> DopBase:
|
41
|
-
return self._dop
|
42
|
-
|
43
|
-
@deprecated(details="use .dop") # type: ignore[misc]
|
44
|
-
def dop_base(self) -> DopBase:
|
45
|
-
return self._dop
|
odxtools/parameterinfo.py
CHANGED
@@ -73,7 +73,7 @@ def parameter_info(param_list: Iterable[Parameter], quoted_names: bool = False)
|
|
73
73
|
of = StringIO()
|
74
74
|
for param in param_list:
|
75
75
|
if isinstance(param, CodedConstParameter):
|
76
|
-
of.write(f"{q}{param.short_name}{q}: const = {param.
|
76
|
+
of.write(f"{q}{param.short_name}{q}: const = {param.coded_value_raw}\n")
|
77
77
|
continue
|
78
78
|
elif isinstance(param, MatchingRequestParameter):
|
79
79
|
of.write(f"{q}{param.short_name}{q}: <matches request>\n")
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
import warnings
|
3
3
|
from dataclasses import dataclass
|
4
|
-
from typing import Any, Dict, List, Optional
|
4
|
+
from typing import Any, Dict, List, Optional, cast
|
5
5
|
from xml.etree import ElementTree
|
6
6
|
|
7
7
|
from typing_extensions import override
|
@@ -20,8 +20,27 @@ from .parameter import Parameter, ParameterType
|
|
20
20
|
@dataclass
|
21
21
|
class CodedConstParameter(Parameter):
|
22
22
|
|
23
|
+
coded_value_raw: str
|
23
24
|
diag_coded_type: DiagCodedType
|
24
|
-
|
25
|
+
|
26
|
+
@property
|
27
|
+
@override
|
28
|
+
def parameter_type(self) -> ParameterType:
|
29
|
+
return "CODED-CONST"
|
30
|
+
|
31
|
+
@property
|
32
|
+
@override
|
33
|
+
def is_required(self) -> bool:
|
34
|
+
return False
|
35
|
+
|
36
|
+
@property
|
37
|
+
@override
|
38
|
+
def is_settable(self) -> bool:
|
39
|
+
return False
|
40
|
+
|
41
|
+
@property
|
42
|
+
def coded_value(self) -> AtomicOdxType:
|
43
|
+
return self._coded_value
|
25
44
|
|
26
45
|
@staticmethod
|
27
46
|
@override
|
@@ -30,18 +49,16 @@ class CodedConstParameter(Parameter):
|
|
30
49
|
|
31
50
|
kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
|
32
51
|
|
52
|
+
coded_value_raw = odxrequire(et_element.findtext("CODED-VALUE"))
|
33
53
|
dct_elem = odxrequire(et_element.find("DIAG-CODED-TYPE"))
|
34
54
|
diag_coded_type = create_any_diag_coded_type_from_et(dct_elem, doc_frags)
|
35
|
-
coded_value = diag_coded_type.base_data_type.from_string(
|
36
|
-
odxrequire(et_element.findtext("CODED-VALUE")))
|
37
55
|
|
38
56
|
return CodedConstParameter(
|
39
|
-
|
57
|
+
coded_value_raw=coded_value_raw, diag_coded_type=diag_coded_type, **kwargs)
|
40
58
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
return "CODED-CONST"
|
59
|
+
def __post_init__(self) -> None:
|
60
|
+
self._coded_value = cast(
|
61
|
+
AtomicOdxType, self.diag_coded_type.base_data_type.from_string(self.coded_value_raw))
|
45
62
|
|
46
63
|
@override
|
47
64
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
@@ -59,16 +76,6 @@ class CodedConstParameter(Parameter):
|
|
59
76
|
def internal_data_type(self) -> DataType:
|
60
77
|
return self.diag_coded_type.base_data_type
|
61
78
|
|
62
|
-
@property
|
63
|
-
@override
|
64
|
-
def is_required(self) -> bool:
|
65
|
-
return False
|
66
|
-
|
67
|
-
@property
|
68
|
-
@override
|
69
|
-
def is_settable(self) -> bool:
|
70
|
-
return False
|
71
|
-
|
72
79
|
@override
|
73
80
|
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
74
81
|
encode_state: EncodeState) -> None:
|
@@ -91,7 +98,7 @@ class CodedConstParameter(Parameter):
|
|
91
98
|
warnings.warn(
|
92
99
|
f"Coded constant parameter does not match! "
|
93
100
|
f"The parameter {self.short_name} expected coded "
|
94
|
-
f"value {str(self.
|
101
|
+
f"value {str(self.coded_value)} but got {str(coded_val)} "
|
95
102
|
f"at byte position {decode_state.cursor_byte_position} "
|
96
103
|
f"in coded message {decode_state.coded_message.hex()}.",
|
97
104
|
DecodeError,
|
@@ -100,12 +107,6 @@ class CodedConstParameter(Parameter):
|
|
100
107
|
|
101
108
|
return coded_val
|
102
109
|
|
103
|
-
@property
|
104
|
-
def _coded_value_str(self) -> str:
|
105
|
-
if isinstance(self.coded_value, bytes):
|
106
|
-
return self.coded_value.hex()
|
107
|
-
return str(self.coded_value)
|
108
|
-
|
109
110
|
def get_description_of_valid_values(self) -> str:
|
110
111
|
"""return a human-understandable description of valid physical values"""
|
111
|
-
return f"Constant internal value: {self.
|
112
|
+
return f"Constant internal value: {str(self.coded_value)}"
|
@@ -16,15 +16,6 @@ from .parameter import Parameter, ParameterType
|
|
16
16
|
@dataclass
|
17
17
|
class DynamicParameter(Parameter):
|
18
18
|
|
19
|
-
@staticmethod
|
20
|
-
@override
|
21
|
-
def from_et(et_element: ElementTree.Element,
|
22
|
-
doc_frags: List[OdxDocFragment]) -> "DynamicParameter":
|
23
|
-
|
24
|
-
kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
|
25
|
-
|
26
|
-
return DynamicParameter(**kwargs)
|
27
|
-
|
28
19
|
@property
|
29
20
|
@override
|
30
21
|
def parameter_type(self) -> ParameterType:
|
@@ -40,6 +31,15 @@ class DynamicParameter(Parameter):
|
|
40
31
|
def is_settable(self) -> bool:
|
41
32
|
raise NotImplementedError(".is_settable for a DynamicParameter")
|
42
33
|
|
34
|
+
@staticmethod
|
35
|
+
@override
|
36
|
+
def from_et(et_element: ElementTree.Element,
|
37
|
+
doc_frags: List[OdxDocFragment]) -> "DynamicParameter":
|
38
|
+
|
39
|
+
kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
|
40
|
+
|
41
|
+
return DynamicParameter(**kwargs)
|
42
|
+
|
43
43
|
@override
|
44
44
|
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
45
45
|
encode_state: EncodeState) -> None:
|
@@ -28,6 +28,24 @@ class LengthKeyParameter(ParameterWithDOP):
|
|
28
28
|
|
29
29
|
odx_id: OdxLinkId
|
30
30
|
|
31
|
+
@property
|
32
|
+
@override
|
33
|
+
def parameter_type(self) -> ParameterType:
|
34
|
+
return "LENGTH-KEY"
|
35
|
+
|
36
|
+
@property
|
37
|
+
@override
|
38
|
+
def is_required(self) -> bool:
|
39
|
+
return False
|
40
|
+
|
41
|
+
@property
|
42
|
+
@override
|
43
|
+
def is_settable(self) -> bool:
|
44
|
+
# length keys can be explicitly set, but they do not need to
|
45
|
+
# be because they can be implicitly determined by the length
|
46
|
+
# of the corresponding field
|
47
|
+
return True
|
48
|
+
|
31
49
|
@staticmethod
|
32
50
|
@override
|
33
51
|
def from_et(et_element: ElementTree.Element,
|
@@ -39,11 +57,6 @@ class LengthKeyParameter(ParameterWithDOP):
|
|
39
57
|
|
40
58
|
return LengthKeyParameter(odx_id=odx_id, **kwargs)
|
41
59
|
|
42
|
-
@property
|
43
|
-
@override
|
44
|
-
def parameter_type(self) -> ParameterType:
|
45
|
-
return "LENGTH-KEY"
|
46
|
-
|
47
60
|
@override
|
48
61
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
49
62
|
result = super()._build_odxlinks()
|
@@ -52,19 +65,6 @@ class LengthKeyParameter(ParameterWithDOP):
|
|
52
65
|
|
53
66
|
return result
|
54
67
|
|
55
|
-
@property
|
56
|
-
@override
|
57
|
-
def is_required(self) -> bool:
|
58
|
-
return False
|
59
|
-
|
60
|
-
@property
|
61
|
-
@override
|
62
|
-
def is_settable(self) -> bool:
|
63
|
-
# length keys can be explicitly set, but they do not need to
|
64
|
-
# be because they can be implicitly determined by the length
|
65
|
-
# of the corresponding field
|
66
|
-
return True
|
67
|
-
|
68
68
|
@override
|
69
69
|
@final
|
70
70
|
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
@@ -19,6 +19,21 @@ class MatchingRequestParameter(Parameter):
|
|
19
19
|
request_byte_position: int
|
20
20
|
byte_length: int
|
21
21
|
|
22
|
+
@property
|
23
|
+
@override
|
24
|
+
def parameter_type(self) -> ParameterType:
|
25
|
+
return "MATCHING-REQUEST-PARAM"
|
26
|
+
|
27
|
+
@property
|
28
|
+
@override
|
29
|
+
def is_required(self) -> bool:
|
30
|
+
return False
|
31
|
+
|
32
|
+
@property
|
33
|
+
@override
|
34
|
+
def is_settable(self) -> bool:
|
35
|
+
return False
|
36
|
+
|
22
37
|
@staticmethod
|
23
38
|
@override
|
24
39
|
def from_et(et_element: ElementTree.Element,
|
@@ -32,25 +47,10 @@ class MatchingRequestParameter(Parameter):
|
|
32
47
|
return MatchingRequestParameter(
|
33
48
|
request_byte_position=request_byte_position, byte_length=byte_length, **kwargs)
|
34
49
|
|
35
|
-
@property
|
36
|
-
@override
|
37
|
-
def parameter_type(self) -> ParameterType:
|
38
|
-
return "MATCHING-REQUEST-PARAM"
|
39
|
-
|
40
50
|
@override
|
41
51
|
def get_static_bit_length(self) -> Optional[int]:
|
42
52
|
return 8 * self.byte_length
|
43
53
|
|
44
|
-
@property
|
45
|
-
@override
|
46
|
-
def is_required(self) -> bool:
|
47
|
-
return False
|
48
|
-
|
49
|
-
@property
|
50
|
-
@override
|
51
|
-
def is_settable(self) -> bool:
|
52
|
-
return False
|
53
|
-
|
54
54
|
@override
|
55
55
|
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
56
56
|
encode_state: EncodeState) -> None:
|