odxtools 9.4.1__py3-none-any.whl → 9.5.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/basevariantpattern.py +38 -0
- odxtools/dataobjectproperty.py +2 -2
- odxtools/diaglayers/basevariant.py +5 -0
- odxtools/diaglayers/basevariantraw.py +7 -1
- odxtools/diaglayers/ecuvariant.py +16 -0
- odxtools/ecuvariantpattern.py +20 -9
- odxtools/encodestate.py +3 -2
- odxtools/matchingbasevariantparameter.py +38 -0
- odxtools/matchingparameter.py +108 -27
- odxtools/minmaxlengthtype.py +3 -3
- odxtools/odxtypes.py +4 -3
- odxtools/standardlengthtype.py +10 -10
- odxtools/subcomponent.py +6 -3
- odxtools/templates/macros/printBaseVariant.xml.jinja2 +4 -9
- odxtools/templates/macros/printBaseVariantPattern.xml.jinja2 +32 -0
- odxtools/templates/macros/printEcuVariantPattern.xml.jinja2 +7 -6
- odxtools/utils.py +4 -0
- odxtools/variantmatcher.py +209 -0
- odxtools/variantpattern.py +38 -0
- odxtools/version.py +2 -2
- {odxtools-9.4.1.dist-info → odxtools-9.5.0.dist-info}/METADATA +1 -1
- {odxtools-9.4.1.dist-info → odxtools-9.5.0.dist-info}/RECORD +26 -23
- {odxtools-9.4.1.dist-info → odxtools-9.5.0.dist-info}/WHEEL +1 -1
- odxtools/createecuvariantpatterns.py +0 -18
- odxtools/ecuvariantmatcher.py +0 -171
- {odxtools-9.4.1.dist-info → odxtools-9.5.0.dist-info}/LICENSE +0 -0
- {odxtools-9.4.1.dist-info → odxtools-9.5.0.dist-info}/entry_points.txt +0 -0
- {odxtools-9.4.1.dist-info → odxtools-9.5.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import List, Union
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from typing_extensions import override
|
7
|
+
|
8
|
+
from .exceptions import odxassert
|
9
|
+
from .matchingbasevariantparameter import MatchingBaseVariantParameter
|
10
|
+
from .matchingparameter import MatchingParameter
|
11
|
+
from .odxlink import OdxDocFragment
|
12
|
+
from .variantpattern import VariantPattern
|
13
|
+
|
14
|
+
|
15
|
+
@dataclass
|
16
|
+
class BaseVariantPattern(VariantPattern):
|
17
|
+
"""Base variant patterns are variant patterns used to identify the
|
18
|
+
base variant of an ECU.
|
19
|
+
"""
|
20
|
+
matching_base_variant_parameters: List[MatchingBaseVariantParameter]
|
21
|
+
|
22
|
+
@override
|
23
|
+
def get_matching_parameters(
|
24
|
+
self) -> Union[List[MatchingParameter], List[MatchingBaseVariantParameter]]:
|
25
|
+
return self.matching_base_variant_parameters
|
26
|
+
|
27
|
+
@staticmethod
|
28
|
+
def from_et(et_element: ElementTree.Element,
|
29
|
+
doc_frags: List[OdxDocFragment]) -> "BaseVariantPattern":
|
30
|
+
|
31
|
+
matching_base_variant_parameters = [
|
32
|
+
MatchingBaseVariantParameter.from_et(mbvp_el, doc_frags)
|
33
|
+
for mbvp_el in et_element.iterfind("MATCHING-BASE-VARIANT-PARAMETERS/"
|
34
|
+
"MATCHING-BASE-VARIANT-PARAMETER")
|
35
|
+
]
|
36
|
+
|
37
|
+
odxassert(len(matching_base_variant_parameters) > 0) # required by ISO 22901-1 Figure 141
|
38
|
+
return BaseVariantPattern(matching_base_variant_parameters=matching_base_variant_parameters)
|
odxtools/dataobjectproperty.py
CHANGED
@@ -17,7 +17,7 @@ from .odxtypes import AtomicOdxType, ParameterValue
|
|
17
17
|
from .physicaltype import PhysicalType
|
18
18
|
from .snrefcontext import SnRefContext
|
19
19
|
from .unit import Unit
|
20
|
-
from .utils import dataclass_fields_asdict
|
20
|
+
from .utils import BytesTypes, dataclass_fields_asdict
|
21
21
|
|
22
22
|
|
23
23
|
@dataclass
|
@@ -120,7 +120,7 @@ class DataObjectProperty(DopBase):
|
|
120
120
|
f"The value {repr(physical_value)} of type {type(physical_value).__name__}"
|
121
121
|
f" is not a valid.")
|
122
122
|
|
123
|
-
if not isinstance(physical_value, (int, float, str,
|
123
|
+
if not isinstance(physical_value, (int, float, str, BytesTypes)):
|
124
124
|
odxraise(f"Invalid type '{type(physical_value).__name__}' for physical value. "
|
125
125
|
f"(Expect atomic type!)")
|
126
126
|
internal_value = self.compu_method.convert_physical_to_internal(physical_value)
|
@@ -6,6 +6,7 @@ from xml.etree import ElementTree
|
|
6
6
|
|
7
7
|
from typing_extensions import override
|
8
8
|
|
9
|
+
from ..basevariantpattern import BaseVariantPattern
|
9
10
|
from ..diagvariable import DiagVariable
|
10
11
|
from ..dyndefinedspec import DynDefinedSpec
|
11
12
|
from ..exceptions import odxassert
|
@@ -38,6 +39,10 @@ class BaseVariant(HierarchyElement):
|
|
38
39
|
def dyn_defined_spec(self) -> Optional[DynDefinedSpec]:
|
39
40
|
return self.base_variant_raw.dyn_defined_spec
|
40
41
|
|
42
|
+
@property
|
43
|
+
def base_variant_pattern(self) -> Optional[BaseVariantPattern]:
|
44
|
+
return self.base_variant_raw.base_variant_pattern
|
45
|
+
|
41
46
|
@property
|
42
47
|
def parent_refs(self) -> List[ParentRef]:
|
43
48
|
return self.base_variant_raw.parent_refs
|
@@ -3,6 +3,7 @@ from dataclasses import dataclass
|
|
3
3
|
from typing import Any, Dict, List, Optional, Union
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
+
from ..basevariantpattern import BaseVariantPattern
|
6
7
|
from ..diagvariable import DiagVariable
|
7
8
|
from ..dyndefinedspec import DynDefinedSpec
|
8
9
|
from ..exceptions import odxraise
|
@@ -23,7 +24,7 @@ class BaseVariantRaw(HierarchyElementRaw):
|
|
23
24
|
diag_variables_raw: List[Union[DiagVariable, OdxLinkRef]]
|
24
25
|
variable_groups: NamedItemList[VariableGroup]
|
25
26
|
dyn_defined_spec: Optional[DynDefinedSpec]
|
26
|
-
|
27
|
+
base_variant_pattern: Optional[BaseVariantPattern]
|
27
28
|
parent_refs: List[ParentRef]
|
28
29
|
|
29
30
|
@property
|
@@ -63,6 +64,10 @@ class BaseVariantRaw(HierarchyElementRaw):
|
|
63
64
|
if (dds_elem := et_element.find("DYN-DEFINED-SPEC")) is not None:
|
64
65
|
dyn_defined_spec = DynDefinedSpec.from_et(dds_elem, doc_frags)
|
65
66
|
|
67
|
+
base_variant_pattern = None
|
68
|
+
if (bvp_elem := et_element.find("BASE-VARIANT-PATTERN")) is not None:
|
69
|
+
base_variant_pattern = BaseVariantPattern.from_et(bvp_elem, doc_frags)
|
70
|
+
|
66
71
|
parent_refs = [
|
67
72
|
ParentRef.from_et(pr_elem, doc_frags)
|
68
73
|
for pr_elem in et_element.iterfind("PARENT-REFS/PARENT-REF")
|
@@ -72,6 +77,7 @@ class BaseVariantRaw(HierarchyElementRaw):
|
|
72
77
|
diag_variables_raw=diag_variables_raw,
|
73
78
|
variable_groups=variable_groups,
|
74
79
|
dyn_defined_spec=dyn_defined_spec,
|
80
|
+
base_variant_pattern=base_variant_pattern,
|
75
81
|
parent_refs=parent_refs,
|
76
82
|
**kwargs)
|
77
83
|
|
@@ -14,6 +14,7 @@ from ..nameditemlist import NamedItemList
|
|
14
14
|
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkRef
|
15
15
|
from ..parentref import ParentRef
|
16
16
|
from ..variablegroup import HasVariableGroups, VariableGroup
|
17
|
+
from .basevariant import BaseVariant
|
17
18
|
from .diaglayer import DiagLayer
|
18
19
|
from .ecuvariantraw import EcuVariantRaw
|
19
20
|
from .hierarchyelement import HierarchyElement
|
@@ -38,6 +39,21 @@ class EcuVariant(HierarchyElement):
|
|
38
39
|
def parent_refs(self) -> List[ParentRef]:
|
39
40
|
return self.ecu_variant_raw.parent_refs
|
40
41
|
|
42
|
+
@property
|
43
|
+
def base_variant(self) -> Optional[BaseVariant]:
|
44
|
+
"""Return the base variant for the ECU variant
|
45
|
+
|
46
|
+
The ODX specification allows at a single base variant for each
|
47
|
+
ECU variant, cf checker rule 50 of appendix B.2 of the
|
48
|
+
specification document.
|
49
|
+
|
50
|
+
"""
|
51
|
+
for pr in self.ecu_variant_raw.parent_refs:
|
52
|
+
if isinstance(pr.layer, BaseVariant):
|
53
|
+
return pr.layer
|
54
|
+
|
55
|
+
return None
|
56
|
+
|
41
57
|
@property
|
42
58
|
def ecu_variant_patterns(self) -> List[EcuVariantPattern]:
|
43
59
|
return self.ecu_variant_raw.ecu_variant_patterns
|
odxtools/ecuvariantpattern.py
CHANGED
@@ -1,27 +1,38 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import List
|
3
|
+
from typing import List, Union
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
-
from
|
6
|
+
from typing_extensions import override
|
7
|
+
|
8
|
+
from .exceptions import odxassert
|
9
|
+
from .matchingbasevariantparameter import MatchingBaseVariantParameter
|
7
10
|
from .matchingparameter import MatchingParameter
|
8
11
|
from .odxlink import OdxDocFragment
|
12
|
+
from .variantpattern import VariantPattern
|
9
13
|
|
10
14
|
|
11
15
|
@dataclass
|
12
|
-
class EcuVariantPattern:
|
16
|
+
class EcuVariantPattern(VariantPattern):
|
17
|
+
"""ECU variant patterns are variant patterns used to identify the
|
18
|
+
concrete variant of an ECU.
|
19
|
+
"""
|
13
20
|
matching_parameters: List[MatchingParameter]
|
14
21
|
|
22
|
+
@override
|
23
|
+
def get_matching_parameters(
|
24
|
+
self) -> Union[List[MatchingParameter], List[MatchingBaseVariantParameter]]:
|
25
|
+
return self.matching_parameters
|
26
|
+
|
15
27
|
@staticmethod
|
16
28
|
def from_et(et_element: ElementTree.Element,
|
17
29
|
doc_frags: List[OdxDocFragment]) -> "EcuVariantPattern":
|
18
30
|
|
19
|
-
|
20
|
-
|
21
|
-
matching_params = [
|
31
|
+
matching_parameters = [
|
22
32
|
MatchingParameter.from_et(mp_el, doc_frags)
|
23
|
-
for mp_el in
|
33
|
+
for mp_el in et_element.iterfind("MATCHING-PARAMETERS/"
|
34
|
+
"MATCHING-PARAMETER")
|
24
35
|
]
|
25
36
|
|
26
|
-
odxassert(len(
|
27
|
-
return EcuVariantPattern(
|
37
|
+
odxassert(len(matching_parameters) > 0) # required by ISO 22901-1 Figure 141
|
38
|
+
return EcuVariantPattern(matching_parameters=matching_parameters)
|
odxtools/encodestate.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
import warnings
|
3
3
|
from dataclasses import dataclass, field
|
4
|
-
from typing import TYPE_CHECKING, Dict, List, Optional,
|
4
|
+
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
8
|
from .odxtypes import AtomicOdxType, DataType, ParameterValue
|
9
|
+
from .utils import BytesTypes
|
9
10
|
|
10
11
|
try:
|
11
12
|
import bitstruct.c as bitstruct
|
@@ -97,7 +98,7 @@ class EncodeState:
|
|
97
98
|
|
98
99
|
# Deal with raw byte fields, ...
|
99
100
|
if base_data_type == DataType.A_BYTEFIELD:
|
100
|
-
if not isinstance(internal_value,
|
101
|
+
if not isinstance(internal_value, BytesTypes):
|
101
102
|
odxraise(f"{internal_value!r} is not a bytefield", EncodeError)
|
102
103
|
return
|
103
104
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import List, Optional
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from .matchingparameter import MatchingParameter
|
7
|
+
from .odxlink import OdxDocFragment
|
8
|
+
from .odxtypes import odxstr_to_bool
|
9
|
+
from .utils import dataclass_fields_asdict
|
10
|
+
|
11
|
+
|
12
|
+
@dataclass
|
13
|
+
class MatchingBaseVariantParameter(MatchingParameter):
|
14
|
+
"""A description of a parameter used for base variant matching.
|
15
|
+
|
16
|
+
This is very similar to `MatchingParameter` for ECU variant
|
17
|
+
matching, but `MatchingBaseVariantParameter` features the
|
18
|
+
additional subtag `USE-PHYSICAL-ADDRESSING`.
|
19
|
+
"""
|
20
|
+
|
21
|
+
use_physical_addressing_raw: Optional[bool]
|
22
|
+
|
23
|
+
@property
|
24
|
+
def use_physical_addressing(self) -> bool:
|
25
|
+
return self.use_physical_addressing_raw in [None, True]
|
26
|
+
|
27
|
+
@staticmethod
|
28
|
+
def from_et(et_element: ElementTree.Element,
|
29
|
+
doc_frags: List[OdxDocFragment]) -> "MatchingBaseVariantParameter":
|
30
|
+
|
31
|
+
kwargs = dataclass_fields_asdict(MatchingParameter.from_et(et_element, doc_frags))
|
32
|
+
|
33
|
+
use_physical_addressing_raw = odxstr_to_bool(et_element.findtext("USE-PHYSICAL-ADDRESSING"))
|
34
|
+
|
35
|
+
return MatchingBaseVariantParameter(
|
36
|
+
use_physical_addressing_raw=use_physical_addressing_raw,
|
37
|
+
**kwargs,
|
38
|
+
)
|
odxtools/matchingparameter.py
CHANGED
@@ -1,58 +1,139 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import List
|
3
|
+
from typing import Any, Dict, List, Optional, cast
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
-
from .
|
7
|
-
from .
|
8
|
-
from .
|
6
|
+
from .diaglayers.diaglayer import DiagLayer
|
7
|
+
from .diagnostictroublecode import DiagnosticTroubleCode
|
8
|
+
from .diagservice import DiagService
|
9
|
+
from .exceptions import odxraise, odxrequire
|
10
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, resolve_snref
|
11
|
+
from .odxtypes import ParameterValue, ParameterValueDict
|
12
|
+
from .snrefcontext import SnRefContext
|
13
|
+
from .utils import BytesTypes
|
9
14
|
|
10
15
|
|
11
16
|
@dataclass
|
12
17
|
class MatchingParameter:
|
13
|
-
"""According to ISO 22901, a MatchingParameter contains a string
|
14
|
-
the active ECU variant. Moreover, it
|
15
|
-
|
18
|
+
"""According to ISO 22901, a MatchingParameter contains a string
|
19
|
+
value identifying the active ECU or base variant. Moreover, it
|
20
|
+
references a DIAG-COMM via snref and one of its positive
|
21
|
+
response's OUT-PARAM-IF via snref or snpathref.
|
22
|
+
|
23
|
+
Unlike other parameters defined in the `parameters` package, a
|
24
|
+
MatchingParameter is not transferred over the network.
|
16
25
|
|
17
|
-
Unlike other parameters defined in the `parameters` package, a MatchingParameter is
|
18
|
-
not transferred over the network.
|
19
26
|
"""
|
20
27
|
|
21
|
-
# datatype according to ISO 22901-1 Figure 141
|
22
28
|
expected_value: str
|
23
29
|
diag_comm_snref: str
|
24
|
-
out_param_if: str
|
25
30
|
|
26
|
-
|
27
|
-
|
28
|
-
|
31
|
+
# be aware that the checker rules 23 and 110 contradict each other
|
32
|
+
# here: the first specifies that the referenced parameter must be
|
33
|
+
# present in *all* positive responses of the referenced service,
|
34
|
+
# whilst the latter mandates it to be present least one positive
|
35
|
+
# or negative response. What it probably actually wants to say is
|
36
|
+
# that any response that can possibly be received shall exhibit
|
37
|
+
# the referenced parameter.
|
38
|
+
out_param_if_snref: Optional[str]
|
39
|
+
out_param_if_snpathref: Optional[str]
|
29
40
|
|
30
41
|
@staticmethod
|
31
42
|
def from_et(et_element: ElementTree.Element,
|
32
43
|
doc_frags: List[OdxDocFragment]) -> "MatchingParameter":
|
33
44
|
|
34
45
|
expected_value = odxrequire(et_element.findtext("EXPECTED-VALUE"))
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
if out_param_snref_el is not None:
|
41
|
-
|
42
|
-
elif out_param_snpathref_el is not None:
|
43
|
-
|
44
|
-
|
46
|
+
diag_comm_snref = odxrequire(
|
47
|
+
odxrequire(et_element.find("DIAG-COMM-SNREF")).get("SHORT-NAME"))
|
48
|
+
|
49
|
+
out_param_if_snref = None
|
50
|
+
out_param_if_snpathref = None
|
51
|
+
if (out_param_snref_el := et_element.find("OUT-PARAM-IF-SNREF")) is not None:
|
52
|
+
out_param_if_snref = odxrequire(out_param_snref_el.get("SHORT-NAME"))
|
53
|
+
elif (out_param_snpathref_el := et_element.find("OUT-PARAM-IF-SNPATHREF")) is not None:
|
54
|
+
out_param_if_snpathref = odxrequire(out_param_snpathref_el.get("SHORT-NAME-PATH"))
|
55
|
+
else:
|
45
56
|
odxraise("Output parameter must not left unspecified")
|
46
57
|
|
47
58
|
return MatchingParameter(
|
48
59
|
expected_value=expected_value,
|
49
60
|
diag_comm_snref=diag_comm_snref,
|
50
|
-
|
61
|
+
out_param_if_snref=out_param_if_snref,
|
62
|
+
out_param_if_snpathref=out_param_if_snpathref,
|
51
63
|
)
|
52
64
|
|
53
|
-
def
|
65
|
+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
66
|
+
return {}
|
67
|
+
|
68
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
69
|
+
pass
|
70
|
+
|
71
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
72
|
+
# note that we do not resolve the SNREF to the diag layer here
|
73
|
+
# because it is a component which changes depending on the
|
74
|
+
# execution context and for variant patterns the execution
|
75
|
+
# context is highly volatile w.r.t. the diag layer in question
|
76
|
+
pass
|
77
|
+
|
78
|
+
def get_ident_service(self, diag_layer: DiagLayer) -> DiagService:
|
79
|
+
return resolve_snref(self.diag_comm_snref, diag_layer.services, DiagService)
|
80
|
+
|
81
|
+
def matches(self, param_dict: ParameterValueDict) -> bool:
|
54
82
|
"""
|
55
83
|
Returns true iff the provided identification value matches this MatchingParameter's
|
56
84
|
expected value.
|
57
85
|
"""
|
58
|
-
|
86
|
+
|
87
|
+
if self.out_param_if_snref is not None:
|
88
|
+
snpath_chunks = [self.out_param_if_snref]
|
89
|
+
elif self.out_param_if_snpathref is not None:
|
90
|
+
snpath_chunks = self.out_param_if_snpathref.split(".")
|
91
|
+
else:
|
92
|
+
odxraise("no out_param_if specified")
|
93
|
+
return False
|
94
|
+
|
95
|
+
return self.__matches(param_dict, snpath_chunks)
|
96
|
+
|
97
|
+
def __matches(self, param_dict: ParameterValue, snpath_chunks: List[str]) -> bool:
|
98
|
+
if len(snpath_chunks) == 0:
|
99
|
+
parameter_value = param_dict
|
100
|
+
if isinstance(parameter_value, dict):
|
101
|
+
odxraise(f"Parameter must not be a structure")
|
102
|
+
return False
|
103
|
+
|
104
|
+
if isinstance(parameter_value, float):
|
105
|
+
# allow a slight tolerance if the expected value is
|
106
|
+
# floating point
|
107
|
+
return abs(float(self.expected_value) - parameter_value) < 1e-8
|
108
|
+
elif isinstance(parameter_value, BytesTypes):
|
109
|
+
return parameter_value.hex().upper() == self.expected_value.upper()
|
110
|
+
elif isinstance(parameter_value, DiagnosticTroubleCode):
|
111
|
+
# TODO: what happens if non-numerical DTCs like
|
112
|
+
# "U123456" are specified? Is specifying DTCs even
|
113
|
+
# allowed in variant patterns?
|
114
|
+
return hex(parameter_value.trouble_code).upper() == self.expected_value.upper()
|
115
|
+
else:
|
116
|
+
return self.expected_value == str(parameter_value)
|
117
|
+
|
118
|
+
if not isinstance(param_dict, dict):
|
119
|
+
odxraise(f"Parameter {snpath_chunks[0]} must be a structure")
|
120
|
+
return False
|
121
|
+
|
122
|
+
sub_value = param_dict.get(snpath_chunks[0])
|
123
|
+
if sub_value is None:
|
124
|
+
return False
|
125
|
+
|
126
|
+
if isinstance(sub_value, tuple) and len(sub_value) == 2:
|
127
|
+
# table struct parameter
|
128
|
+
sub_value = sub_value[1]
|
129
|
+
|
130
|
+
if isinstance(sub_value, list):
|
131
|
+
# the spec mandates that if any item of a field matches,
|
132
|
+
# the parameter as a whole matches
|
133
|
+
for x in sub_value:
|
134
|
+
if self.__matches(x, snpath_chunks[1:]):
|
135
|
+
return True
|
136
|
+
|
137
|
+
return False
|
138
|
+
|
139
|
+
return self.__matches(cast(ParameterValue, sub_value), snpath_chunks[1:])
|
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 DecodeError, EncodeError, odxassert, odxraise, odxrequire
|
13
|
+
from .exceptions import (DecodeError, EncodeError, odxassert, odxraise, odxrequire)
|
14
14
|
from .odxlink import OdxDocFragment
|
15
15
|
from .odxtypes import AtomicOdxType, DataType
|
16
|
-
from .utils import dataclass_fields_asdict
|
16
|
+
from .utils import BytesTypes, dataclass_fields_asdict
|
17
17
|
|
18
18
|
|
19
19
|
class Termination(Enum):
|
@@ -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/odxtypes.py
CHANGED
@@ -5,6 +5,7 @@ from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, Optional, Tupl
|
|
5
5
|
from xml.etree import ElementTree
|
6
6
|
|
7
7
|
from .exceptions import odxassert, odxraise, odxrequire
|
8
|
+
from .utils import BytesTypes
|
8
9
|
|
9
10
|
if TYPE_CHECKING:
|
10
11
|
from odxtools.diagnostictroublecode import DiagnosticTroubleCode
|
@@ -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/standardlengthtype.py
CHANGED
@@ -3,7 +3,7 @@ from dataclasses import dataclass
|
|
3
3
|
from typing import List, Literal, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
-
from typing_extensions import
|
6
|
+
from typing_extensions import override
|
7
7
|
|
8
8
|
from .decodestate import DecodeState
|
9
9
|
from .diagcodedtype import DctType, DiagCodedType
|
@@ -11,7 +11,7 @@ from .encodestate import EncodeState
|
|
11
11
|
from .exceptions import odxassert, odxraise, odxrequire
|
12
12
|
from .odxlink import OdxDocFragment
|
13
13
|
from .odxtypes import AtomicOdxType, DataType, odxstr_to_bool
|
14
|
-
from .utils import dataclass_fields_asdict
|
14
|
+
from .utils import BytesTypes, dataclass_fields_asdict
|
15
15
|
|
16
16
|
|
17
17
|
@dataclass
|
@@ -91,7 +91,7 @@ class StandardLengthType(DiagCodedType):
|
|
91
91
|
return used_mask.to_bytes((bit_sz + 7) // 8, endianness)
|
92
92
|
|
93
93
|
sz: int
|
94
|
-
if isinstance(internal_value,
|
94
|
+
if isinstance(internal_value, BytesTypes):
|
95
95
|
sz = len(bytes(internal_value))
|
96
96
|
else:
|
97
97
|
sz = (odxrequire(self.get_static_bit_length()) + 7) // 8
|
@@ -107,7 +107,7 @@ class StandardLengthType(DiagCodedType):
|
|
107
107
|
|
108
108
|
if self.is_condensed:
|
109
109
|
int_value: int
|
110
|
-
if isinstance(internal_value,
|
110
|
+
if isinstance(internal_value, BytesTypes):
|
111
111
|
int_value = int.from_bytes(internal_value, 'big')
|
112
112
|
elif isinstance(internal_value, int):
|
113
113
|
int_value = internal_value
|
@@ -126,14 +126,14 @@ class StandardLengthType(DiagCodedType):
|
|
126
126
|
|
127
127
|
mask_bit += 1
|
128
128
|
|
129
|
-
if isinstance(internal_value,
|
129
|
+
if isinstance(internal_value, BytesTypes):
|
130
130
|
return result.to_bytes(len(internal_value), 'big')
|
131
131
|
|
132
132
|
return result
|
133
133
|
|
134
134
|
if isinstance(internal_value, int):
|
135
135
|
return internal_value & self.bit_mask
|
136
|
-
if isinstance(internal_value,
|
136
|
+
if isinstance(internal_value, BytesTypes):
|
137
137
|
int_value = int.from_bytes(internal_value, 'big')
|
138
138
|
int_value &= self.bit_mask
|
139
139
|
return int_value.to_bytes(len(bytes(internal_value)), 'big')
|
@@ -146,7 +146,7 @@ class StandardLengthType(DiagCodedType):
|
|
146
146
|
return raw_value
|
147
147
|
if self.is_condensed:
|
148
148
|
int_value: int
|
149
|
-
if isinstance(raw_value,
|
149
|
+
if isinstance(raw_value, BytesTypes):
|
150
150
|
int_value = int.from_bytes(raw_value, 'big')
|
151
151
|
elif isinstance(raw_value, int):
|
152
152
|
int_value = raw_value
|
@@ -164,16 +164,16 @@ class StandardLengthType(DiagCodedType):
|
|
164
164
|
|
165
165
|
mask_bit += 1
|
166
166
|
|
167
|
-
if isinstance(raw_value,
|
167
|
+
if isinstance(raw_value, BytesTypes):
|
168
168
|
return result.to_bytes(len(raw_value), 'big')
|
169
169
|
|
170
170
|
return result
|
171
171
|
if isinstance(raw_value, int):
|
172
172
|
return raw_value & self.bit_mask
|
173
|
-
if isinstance(raw_value,
|
173
|
+
if isinstance(raw_value, BytesTypes):
|
174
174
|
int_value = int.from_bytes(raw_value, 'big')
|
175
175
|
int_value &= self.bit_mask
|
176
|
-
return int_value
|
176
|
+
return int_value.to_bytes(len(raw_value), 'big')
|
177
177
|
|
178
178
|
odxraise(f'Can not apply a bit_mask on a value of type {type(raw_value)}')
|
179
179
|
return raw_value
|
odxtools/subcomponent.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, Optional
|
3
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .diagnostictroublecode import DiagnosticTroubleCode
|
@@ -10,7 +10,6 @@ from .element import IdentifiableElement, NamedElement
|
|
10
10
|
from .environmentdata import EnvironmentData
|
11
11
|
from .environmentdatadescription import EnvironmentDataDescription
|
12
12
|
from .exceptions import odxraise, odxrequire
|
13
|
-
from .matchingparameter import MatchingParameter
|
14
13
|
from .nameditemlist import NamedItemList
|
15
14
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
16
15
|
from .parameters.parameter import Parameter
|
@@ -19,14 +18,18 @@ from .table import Table
|
|
19
18
|
from .tablerow import TableRow
|
20
19
|
from .utils import dataclass_fields_asdict
|
21
20
|
|
21
|
+
if TYPE_CHECKING:
|
22
|
+
from .matchingparameter import MatchingParameter
|
23
|
+
|
22
24
|
|
23
25
|
@dataclass
|
24
26
|
class SubComponentPattern:
|
25
|
-
matching_parameters: List[MatchingParameter]
|
27
|
+
matching_parameters: List["MatchingParameter"]
|
26
28
|
|
27
29
|
@staticmethod
|
28
30
|
def from_et(et_element: ElementTree.Element,
|
29
31
|
doc_frags: List[OdxDocFragment]) -> "SubComponentPattern":
|
32
|
+
from .matchingparameter import MatchingParameter
|
30
33
|
|
31
34
|
matching_parameters = [
|
32
35
|
MatchingParameter.from_et(el, doc_frags)
|
@@ -6,6 +6,7 @@
|
|
6
6
|
{%- import('macros/printHierarchyElement.xml.jinja2') as phe %}
|
7
7
|
{%- import('macros/printComparamRef.xml.jinja2') as pcom %}
|
8
8
|
{%- import('macros/printParentRef.xml.jinja2') as pparref %}
|
9
|
+
{%- import('macros/printBaseVariantPattern.xml.jinja2') as pbvp %}
|
9
10
|
|
10
11
|
{%- macro printBaseVariant(base_variant) -%}
|
11
12
|
<BASE-VARIANT {{- phe.printHierarchyElementAttribs(base_variant) -}}>
|
@@ -29,18 +30,12 @@
|
|
29
30
|
{%- endif %}
|
30
31
|
|
31
32
|
{%- if dlr.dyn_defined_spec %}
|
32
|
-
{{ pdynspec.printPrintDefinedSpec(dlr.dyn_defined_spec)|indent(
|
33
|
+
{{ pdynspec.printPrintDefinedSpec(dlr.dyn_defined_spec)|indent(2) }}
|
33
34
|
{%- endif %}
|
34
35
|
|
35
|
-
{
|
36
|
-
{
|
37
|
-
<BASE-VARIANT-PATTERNS>
|
38
|
-
{%- for vp in dlr.base_variant_patterns -%}
|
39
|
-
{{ pvpat.printBaseVariantPattern(vp)|indent(4) }}
|
40
|
-
{%- endfor -%}
|
41
|
-
</BASE-VARIANT-PATTERNS>
|
36
|
+
{%- if dlr.base_variant_pattern is not none %}
|
37
|
+
{{ pbvp.printBaseVariantPattern(dlr.base_variant_pattern)|indent(2) }}
|
42
38
|
{%- endif %}
|
43
|
-
#}
|
44
39
|
|
45
40
|
{%- if dlr.parent_refs %}
|
46
41
|
<PARENT-REFS>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
{#- -*- mode: sgml; tab-width: 1; indent-tabs-mode: nil -*-
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
-#}
|
5
|
+
|
6
|
+
{%- macro printMatchingBaseVariantParameter(mbvp) -%}
|
7
|
+
<MATCHING-BASE-VARIANT-PARAMETER>
|
8
|
+
<EXPECTED-VALUE>{{mbvp.expected_value | e}}</EXPECTED-VALUE>
|
9
|
+
{%- if mbvp.use_physical_addressing_raw is true %}
|
10
|
+
<USE-PHYSICAL-ADDRESSING>true</USE-PHYSICAL-ADDRESSING>
|
11
|
+
{%- elif mbvp.use_physical_addressing_raw is false %}
|
12
|
+
<USE-PHYSICAL-ADDRESSING>false</USE-PHYSICAL-ADDRESSING>
|
13
|
+
{%- endif %}
|
14
|
+
<DIAG-COMM-SNREF SHORT-NAME="{{mbvp.diag_comm_snref}}" />
|
15
|
+
{%- if mbvp.out_param_if_snref is not none %}
|
16
|
+
<OUT-PARAM-IF-SNREF SHORT-NAME="{{mbvp.out_param_if_snref}}" />
|
17
|
+
{%- endif %}
|
18
|
+
{%- if mbvp.out_param_if_snpathref is not none %}
|
19
|
+
<OUT-PARAM-IF-SNPATHREF SHORT-NAME-PATH="{{mbvp.out_param_if_snpathref}}" />
|
20
|
+
{%- endif %}
|
21
|
+
</MATCHING-BASE-VARIANT-PARAMETER>
|
22
|
+
{%- endmacro -%}
|
23
|
+
|
24
|
+
{%- macro printBaseVariantPattern(vp) -%}
|
25
|
+
<BASE-VARIANT-PATTERN>
|
26
|
+
<MATCHING-BASE-VARIANT-PARAMETERS>
|
27
|
+
{%- for mbvp in vp.matching_base_variant_parameters %}
|
28
|
+
{{ printMatchingBaseVariantParameter(mbvp) | indent(2) }}
|
29
|
+
{%- endfor %}
|
30
|
+
</MATCHING-BASE-VARIANT-PARAMETERS>
|
31
|
+
</BASE-VARIANT-PATTERN>
|
32
|
+
{%- endmacro -%}
|