odxtools 6.6.1__py3-none-any.whl → 9.3.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/__init__.py +7 -5
- odxtools/additionalaudience.py +3 -5
- odxtools/admindata.py +5 -7
- odxtools/audience.py +10 -13
- odxtools/basecomparam.py +3 -5
- odxtools/basicstructure.py +55 -241
- odxtools/cli/_parser_utils.py +16 -1
- odxtools/cli/_print_utils.py +169 -134
- odxtools/cli/browse.py +127 -103
- odxtools/cli/compare.py +114 -87
- odxtools/cli/decode.py +2 -1
- odxtools/cli/dummy_sub_parser.py +3 -1
- odxtools/cli/find.py +2 -1
- odxtools/cli/list.py +26 -16
- odxtools/cli/main.py +1 -0
- odxtools/cli/snoop.py +32 -6
- odxtools/codec.py +211 -0
- odxtools/commrelation.py +122 -0
- odxtools/companydata.py +5 -7
- odxtools/companydocinfo.py +7 -8
- odxtools/companyrevisioninfo.py +3 -5
- odxtools/companyspecificinfo.py +8 -9
- odxtools/comparam.py +4 -6
- odxtools/comparaminstance.py +14 -14
- odxtools/comparamspec.py +16 -54
- odxtools/comparamsubset.py +22 -62
- odxtools/complexcomparam.py +5 -7
- odxtools/compumethods/compucodecompumethod.py +63 -0
- odxtools/compumethods/compuconst.py +31 -0
- odxtools/compumethods/compudefaultvalue.py +27 -0
- odxtools/compumethods/compuinternaltophys.py +56 -0
- odxtools/compumethods/compuinversevalue.py +7 -0
- odxtools/compumethods/compumethod.py +94 -15
- odxtools/compumethods/compuphystointernal.py +56 -0
- odxtools/compumethods/compurationalcoeffs.py +20 -9
- odxtools/compumethods/compuscale.py +67 -32
- odxtools/compumethods/createanycompumethod.py +31 -172
- odxtools/compumethods/identicalcompumethod.py +31 -6
- odxtools/compumethods/limit.py +70 -36
- odxtools/compumethods/linearcompumethod.py +70 -181
- odxtools/compumethods/linearsegment.py +190 -0
- odxtools/compumethods/ratfunccompumethod.py +106 -0
- odxtools/compumethods/ratfuncsegment.py +87 -0
- odxtools/compumethods/scalelinearcompumethod.py +132 -26
- odxtools/compumethods/scaleratfunccompumethod.py +113 -0
- odxtools/compumethods/tabintpcompumethod.py +123 -92
- odxtools/compumethods/texttablecompumethod.py +117 -57
- odxtools/createanydiagcodedtype.py +10 -67
- odxtools/database.py +167 -87
- odxtools/dataobjectproperty.py +25 -32
- odxtools/decodestate.py +14 -17
- odxtools/description.py +47 -0
- odxtools/determinenumberofitems.py +4 -5
- odxtools/diagcodedtype.py +37 -106
- odxtools/diagcomm.py +24 -12
- odxtools/diagdatadictionaryspec.py +120 -96
- odxtools/diaglayercontainer.py +46 -54
- odxtools/diaglayers/basevariant.py +128 -0
- odxtools/diaglayers/basevariantraw.py +123 -0
- odxtools/diaglayers/diaglayer.py +432 -0
- odxtools/{diaglayerraw.py → diaglayers/diaglayerraw.py} +105 -120
- odxtools/diaglayers/diaglayertype.py +42 -0
- odxtools/diaglayers/ecushareddata.py +96 -0
- odxtools/diaglayers/ecushareddataraw.py +87 -0
- odxtools/diaglayers/ecuvariant.py +124 -0
- odxtools/diaglayers/ecuvariantraw.py +129 -0
- odxtools/diaglayers/functionalgroup.py +110 -0
- odxtools/diaglayers/functionalgroupraw.py +106 -0
- odxtools/{diaglayer.py → diaglayers/hierarchyelement.py} +273 -472
- odxtools/diaglayers/hierarchyelementraw.py +58 -0
- odxtools/diaglayers/protocol.py +64 -0
- odxtools/diaglayers/protocolraw.py +91 -0
- odxtools/diagnostictroublecode.py +8 -9
- odxtools/diagservice.py +57 -44
- odxtools/diagvariable.py +113 -0
- odxtools/docrevision.py +5 -7
- odxtools/dopbase.py +15 -15
- odxtools/dtcdop.py +170 -50
- odxtools/dynamicendmarkerfield.py +134 -0
- odxtools/dynamiclengthfield.py +47 -42
- odxtools/dyndefinedspec.py +177 -0
- odxtools/dynenddopref.py +38 -0
- odxtools/ecuvariantmatcher.py +6 -7
- odxtools/element.py +13 -15
- odxtools/encodestate.py +199 -22
- odxtools/endofpdufield.py +31 -18
- odxtools/environmentdata.py +8 -1
- odxtools/environmentdatadescription.py +198 -36
- odxtools/exceptions.py +11 -2
- odxtools/field.py +10 -10
- odxtools/functionalclass.py +3 -5
- odxtools/inputparam.py +3 -12
- odxtools/internalconstr.py +14 -5
- odxtools/isotp_state_machine.py +14 -6
- odxtools/leadinglengthinfotype.py +37 -18
- odxtools/library.py +66 -0
- odxtools/loadfile.py +64 -0
- odxtools/matchingparameter.py +3 -3
- odxtools/message.py +0 -7
- odxtools/minmaxlengthtype.py +61 -33
- odxtools/modification.py +3 -5
- odxtools/multiplexer.py +135 -75
- odxtools/multiplexercase.py +39 -18
- odxtools/multiplexerdefaultcase.py +15 -12
- odxtools/multiplexerswitchkey.py +4 -5
- odxtools/nameditemlist.py +33 -8
- odxtools/negoutputparam.py +3 -5
- odxtools/odxcategory.py +83 -0
- odxtools/odxlink.py +62 -53
- odxtools/odxtypes.py +93 -8
- odxtools/outputparam.py +5 -16
- odxtools/parameterinfo.py +219 -61
- odxtools/parameters/codedconstparameter.py +45 -32
- odxtools/parameters/createanyparameter.py +19 -193
- odxtools/parameters/dynamicparameter.py +25 -4
- odxtools/parameters/lengthkeyparameter.py +83 -25
- odxtools/parameters/matchingrequestparameter.py +48 -18
- odxtools/parameters/nrcconstparameter.py +76 -54
- odxtools/parameters/parameter.py +97 -73
- odxtools/parameters/parameterwithdop.py +41 -38
- odxtools/parameters/physicalconstantparameter.py +41 -20
- odxtools/parameters/reservedparameter.py +36 -18
- odxtools/parameters/systemparameter.py +74 -7
- odxtools/parameters/tableentryparameter.py +47 -7
- odxtools/parameters/tablekeyparameter.py +142 -55
- odxtools/parameters/tablestructparameter.py +79 -58
- odxtools/parameters/valueparameter.py +39 -21
- odxtools/paramlengthinfotype.py +56 -33
- odxtools/parentref.py +20 -3
- odxtools/physicaldimension.py +3 -8
- odxtools/progcode.py +26 -11
- odxtools/protstack.py +3 -5
- odxtools/py.typed +0 -0
- odxtools/relateddoc.py +7 -9
- odxtools/request.py +120 -10
- odxtools/response.py +123 -23
- odxtools/scaleconstr.py +14 -8
- odxtools/servicebinner.py +1 -1
- odxtools/singleecujob.py +12 -10
- odxtools/snrefcontext.py +29 -0
- odxtools/specialdata.py +3 -5
- odxtools/specialdatagroup.py +7 -9
- odxtools/specialdatagroupcaption.py +3 -6
- odxtools/standardlengthtype.py +80 -14
- odxtools/state.py +3 -5
- odxtools/statechart.py +13 -19
- odxtools/statetransition.py +8 -18
- odxtools/staticfield.py +107 -0
- odxtools/subcomponent.py +288 -0
- odxtools/swvariable.py +21 -0
- odxtools/table.py +9 -9
- odxtools/tablerow.py +30 -15
- odxtools/teammember.py +3 -5
- odxtools/templates/comparam-spec.odx-c.xml.jinja2 +4 -24
- odxtools/templates/comparam-subset.odx-cs.xml.jinja2 +5 -26
- odxtools/templates/diag_layer_container.odx-d.xml.jinja2 +15 -31
- odxtools/templates/{index.xml.xml.jinja2 → index.xml.jinja2} +1 -1
- odxtools/templates/macros/printAudience.xml.jinja2 +1 -1
- odxtools/templates/macros/printBaseVariant.xml.jinja2 +53 -0
- odxtools/templates/macros/printCompanyData.xml.jinja2 +4 -7
- odxtools/templates/macros/printComparam.xml.jinja2 +6 -4
- odxtools/templates/macros/printComparamRef.xml.jinja2 +5 -12
- odxtools/templates/macros/printCompuMethod.xml.jinja2 +147 -0
- odxtools/templates/macros/printDOP.xml.jinja2 +27 -137
- odxtools/templates/macros/printDescription.xml.jinja2 +18 -0
- odxtools/templates/macros/printDiagComm.xml.jinja2 +1 -1
- odxtools/templates/macros/printDiagLayer.xml.jinja2 +222 -0
- odxtools/templates/macros/printDiagVariable.xml.jinja2 +66 -0
- odxtools/templates/macros/printDynDefinedSpec.xml.jinja2 +48 -0
- odxtools/templates/macros/printDynamicEndmarkerField.xml.jinja2 +16 -0
- odxtools/templates/macros/printDynamicLengthField.xml.jinja2 +1 -1
- odxtools/templates/macros/printEcuSharedData.xml.jinja2 +30 -0
- odxtools/templates/macros/printEcuVariant.xml.jinja2 +53 -0
- odxtools/templates/macros/printEcuVariantPattern.xml.jinja2 +1 -1
- odxtools/templates/macros/printElementId.xml.jinja2 +8 -3
- odxtools/templates/macros/printEndOfPdu.xml.jinja2 +1 -1
- odxtools/templates/macros/printEnvDataDesc.xml.jinja2 +1 -1
- odxtools/templates/macros/printFunctionalClass.xml.jinja2 +1 -1
- odxtools/templates/macros/printFunctionalGroup.xml.jinja2 +40 -0
- odxtools/templates/macros/printHierarchyElement.xml.jinja2 +24 -0
- odxtools/templates/macros/printLibrary.xml.jinja2 +21 -0
- odxtools/templates/macros/printMux.xml.jinja2 +5 -3
- odxtools/templates/macros/printOdxCategory.xml.jinja2 +28 -0
- odxtools/templates/macros/printParam.xml.jinja2 +18 -19
- odxtools/templates/macros/printProtStack.xml.jinja2 +1 -1
- odxtools/templates/macros/printProtocol.xml.jinja2 +30 -0
- odxtools/templates/macros/printRequest.xml.jinja2 +1 -1
- odxtools/templates/macros/printResponse.xml.jinja2 +1 -1
- odxtools/templates/macros/printService.xml.jinja2 +3 -2
- odxtools/templates/macros/printSingleEcuJob.xml.jinja2 +5 -26
- odxtools/templates/macros/printSpecialData.xml.jinja2 +1 -1
- odxtools/templates/macros/printState.xml.jinja2 +1 -1
- odxtools/templates/macros/printStateChart.xml.jinja2 +1 -1
- odxtools/templates/macros/printStateTransition.xml.jinja2 +1 -1
- odxtools/templates/macros/printStaticField.xml.jinja2 +15 -0
- odxtools/templates/macros/printStructure.xml.jinja2 +1 -1
- odxtools/templates/macros/printSubComponent.xml.jinja2 +104 -0
- odxtools/templates/macros/printTable.xml.jinja2 +4 -5
- odxtools/templates/macros/printUnitSpec.xml.jinja2 +3 -5
- odxtools/uds.py +2 -10
- odxtools/unit.py +4 -8
- odxtools/unitgroup.py +3 -5
- odxtools/unitspec.py +17 -17
- odxtools/utils.py +38 -20
- odxtools/variablegroup.py +32 -0
- odxtools/version.py +2 -2
- odxtools/{write_pdx_file.py → writepdxfile.py} +22 -12
- odxtools/xdoc.py +3 -5
- {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/METADATA +44 -33
- odxtools-9.3.0.dist-info/RECORD +228 -0
- {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/WHEEL +1 -1
- odxtools/createcompanydatas.py +0 -17
- odxtools/createsdgs.py +0 -19
- odxtools/diaglayertype.py +0 -30
- odxtools/load_file.py +0 -13
- odxtools/load_odx_d_file.py +0 -6
- odxtools/load_pdx_file.py +0 -8
- odxtools/templates/macros/printVariant.xml.jinja2 +0 -208
- odxtools-6.6.1.dist-info/RECORD +0 -180
- {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/LICENSE +0 -0
- {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/entry_points.txt +0 -0
- {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/top_level.txt +0 -0
@@ -1,38 +1,65 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
-
import warnings
|
3
2
|
from dataclasses import dataclass
|
4
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
|
+
from xml.etree import ElementTree
|
5
5
|
|
6
|
+
from typing_extensions import override
|
7
|
+
|
8
|
+
from ..createanydiagcodedtype import create_any_diag_coded_type_from_et
|
6
9
|
from ..decodestate import DecodeState
|
7
10
|
from ..diagcodedtype import DiagCodedType
|
8
11
|
from ..encodestate import EncodeState
|
9
|
-
from ..exceptions import
|
10
|
-
from ..odxlink import
|
11
|
-
from ..odxtypes import AtomicOdxType, DataType
|
12
|
+
from ..exceptions import DecodeMismatch, EncodeError, odxraise, odxrequire
|
13
|
+
from ..odxlink import OdxDocFragment, OdxLinkId
|
14
|
+
from ..odxtypes import AtomicOdxType, DataType, ParameterValue
|
15
|
+
from ..utils import dataclass_fields_asdict
|
12
16
|
from .parameter import Parameter, ParameterType
|
13
17
|
|
14
|
-
if TYPE_CHECKING:
|
15
|
-
from ..diaglayer import DiagLayer
|
16
|
-
|
17
18
|
|
18
19
|
@dataclass
|
19
20
|
class NrcConstParameter(Parameter):
|
20
|
-
"""A
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
"""A parameter of type NRC-CONST defines a set of values to be
|
22
|
+
matched for a negative response object to apply
|
23
|
+
|
24
|
+
The behaviour of NRC-CONST parameters is similar to CODED-CONST
|
25
|
+
parameters in that they allow to specify which coding objects
|
26
|
+
apply to a binary string, but in contrast to CODED-CONST
|
27
|
+
parameters they allow to specify multiple values. Thus, the value
|
28
|
+
of a CODED-CONST parameter is usually set using an overlapping
|
29
|
+
VALUE parameter. Since NRC-CONST parameters can only be specified
|
30
|
+
for negative responses, they can thus be regarded as a multiplexer
|
31
|
+
mechanism that is specific to negative responses.
|
25
32
|
|
26
33
|
See ASAM MCD-2 D (ODX), p. 77-79.
|
34
|
+
|
27
35
|
"""
|
28
36
|
|
29
37
|
diag_coded_type: DiagCodedType
|
30
38
|
coded_values: List[AtomicOdxType]
|
31
39
|
|
40
|
+
@staticmethod
|
41
|
+
@override
|
42
|
+
def from_et(et_element: ElementTree.Element,
|
43
|
+
doc_frags: List[OdxDocFragment]) -> "NrcConstParameter":
|
44
|
+
|
45
|
+
kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
|
46
|
+
|
47
|
+
dct_elem = odxrequire(et_element.find("DIAG-CODED-TYPE"))
|
48
|
+
diag_coded_type = create_any_diag_coded_type_from_et(dct_elem, doc_frags)
|
49
|
+
coded_values = [
|
50
|
+
diag_coded_type.base_data_type.from_string(odxrequire(val.text))
|
51
|
+
for val in et_element.iterfind("CODED-VALUES/CODED-VALUE")
|
52
|
+
]
|
53
|
+
|
54
|
+
return NrcConstParameter(
|
55
|
+
diag_coded_type=diag_coded_type, coded_values=coded_values, **kwargs)
|
56
|
+
|
32
57
|
@property
|
58
|
+
@override
|
33
59
|
def parameter_type(self) -> ParameterType:
|
34
60
|
return "NRC-CONST"
|
35
61
|
|
62
|
+
@override
|
36
63
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
37
64
|
result = super()._build_odxlinks()
|
38
65
|
|
@@ -40,12 +67,7 @@ class NrcConstParameter(Parameter):
|
|
40
67
|
|
41
68
|
return result
|
42
69
|
|
43
|
-
|
44
|
-
super()._resolve_odxlinks(odxlinks)
|
45
|
-
|
46
|
-
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
47
|
-
super()._resolve_snrefs(diag_layer)
|
48
|
-
|
70
|
+
@override
|
49
71
|
def get_static_bit_length(self) -> Optional[int]:
|
50
72
|
return self.diag_coded_type.get_static_bit_length()
|
51
73
|
|
@@ -54,52 +76,52 @@ class NrcConstParameter(Parameter):
|
|
54
76
|
return self.diag_coded_type.base_data_type
|
55
77
|
|
56
78
|
@property
|
79
|
+
@override
|
57
80
|
def is_required(self) -> bool:
|
58
81
|
return False
|
59
82
|
|
60
83
|
@property
|
84
|
+
@override
|
61
85
|
def is_settable(self) -> bool:
|
62
86
|
return False
|
63
87
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
+
@override
|
89
|
+
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
90
|
+
encode_state: EncodeState) -> None:
|
91
|
+
# NRC-CONST parameters are not encoding any value on its
|
92
|
+
# own. instead, it is supposed to overlap with a value
|
93
|
+
# parameter.
|
94
|
+
if physical_value is not None:
|
95
|
+
odxraise("The value of NRC-CONST parameters cannot be set directly!", EncodeError)
|
96
|
+
|
97
|
+
# TODO (?): extract the parameter and check if it is one of
|
98
|
+
# the values of self.coded_values. if not, throw an
|
99
|
+
# EncodeMismatch exception! This is probably a bad idea
|
100
|
+
# because the parameter which determines the value of the
|
101
|
+
# NRC-CONST might possibly be specified after the NRC-CONST.
|
102
|
+
|
103
|
+
# move the cursor forward by the size of the parameter
|
104
|
+
bit_pos = encode_state.cursor_bit_position
|
105
|
+
bit_len = self.diag_coded_type.get_static_bit_length()
|
106
|
+
|
107
|
+
if bit_len is None:
|
108
|
+
odxraise("The diag coded type of NRC-CONST parameters must "
|
109
|
+
"exhibit a static size")
|
110
|
+
return
|
111
|
+
|
112
|
+
encode_state.cursor_byte_position += (bit_pos + bit_len + 7) // 8
|
113
|
+
encode_state.cursor_bit_position = 0
|
114
|
+
|
115
|
+
encode_state.emplace_bytes(b'', self.short_name)
|
116
|
+
|
117
|
+
@override
|
118
|
+
def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> AtomicOdxType:
|
119
|
+
# Extract coded value
|
88
120
|
coded_value = self.diag_coded_type.decode_from_pdu(decode_state)
|
89
121
|
|
90
122
|
# Check if the coded value in the message is correct.
|
91
123
|
if coded_value not in self.coded_values:
|
92
|
-
|
93
|
-
f"Coded constant parameter does not match! "
|
94
|
-
f"The parameter {self.short_name} expected a coded "
|
95
|
-
f"value in {str(self.coded_values)} but got {str(coded_value)} "
|
96
|
-
f"at byte position {decode_state.cursor_byte_position} "
|
97
|
-
f"in coded message {decode_state.coded_message.hex()}.",
|
98
|
-
DecodeError,
|
99
|
-
stacklevel=1,
|
100
|
-
)
|
101
|
-
|
102
|
-
decode_state.cursor_byte_position = max(decode_state.cursor_byte_position, orig_cursor)
|
124
|
+
raise DecodeMismatch(f"NRC-CONST parameter {self.short_name} does not apply")
|
103
125
|
|
104
126
|
return coded_value
|
105
127
|
|
odxtools/parameters/parameter.py
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
-
import abc
|
3
2
|
from dataclasses import dataclass
|
4
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Literal, Optional
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from typing_extensions import final, override
|
5
7
|
|
6
8
|
from ..decodestate import DecodeState
|
7
9
|
from ..element import NamedElement
|
8
10
|
from ..encodestate import EncodeState
|
9
|
-
from ..odxlink import OdxLinkDatabase, OdxLinkId
|
11
|
+
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
10
12
|
from ..odxtypes import ParameterValue
|
13
|
+
from ..snrefcontext import SnRefContext
|
11
14
|
from ..specialdatagroup import SpecialDataGroup
|
12
|
-
|
13
|
-
if TYPE_CHECKING:
|
14
|
-
from ..diaglayer import DiagLayer
|
15
|
+
from ..utils import dataclass_fields_asdict
|
15
16
|
|
16
17
|
ParameterType = Literal[
|
17
18
|
"CODED-CONST",
|
@@ -30,12 +31,49 @@ ParameterType = Literal[
|
|
30
31
|
|
31
32
|
|
32
33
|
@dataclass
|
33
|
-
class Parameter(NamedElement
|
34
|
+
class Parameter(NamedElement):
|
35
|
+
"""This class corresponds to POSITIONABLE-PARAM in the ODX
|
36
|
+
specification
|
37
|
+
|
38
|
+
All parameter classes must adhere to the `Codec` type protocol, so
|
39
|
+
`isinstance(param, Codec)` ought to be true. Be aware that, even
|
40
|
+
though the ODX specification seems to make the distinction of
|
41
|
+
"positionable" and "normal" parameters, it does not define any
|
42
|
+
non-positionable parameter types.
|
43
|
+
|
44
|
+
"""
|
45
|
+
oid: Optional[str]
|
34
46
|
byte_position: Optional[int]
|
35
47
|
bit_position: Optional[int]
|
36
48
|
semantic: Optional[str]
|
37
49
|
sdgs: List[SpecialDataGroup]
|
38
50
|
|
51
|
+
@staticmethod
|
52
|
+
@override
|
53
|
+
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Parameter":
|
54
|
+
|
55
|
+
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
|
56
|
+
|
57
|
+
oid = et_element.get("OID")
|
58
|
+
semantic = et_element.get("SEMANTIC")
|
59
|
+
sdgs = [
|
60
|
+
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
61
|
+
]
|
62
|
+
|
63
|
+
byte_position_str = et_element.findtext("BYTE-POSITION")
|
64
|
+
bit_position_str = et_element.findtext("BIT-POSITION")
|
65
|
+
|
66
|
+
byte_position = int(byte_position_str) if byte_position_str is not None else None
|
67
|
+
bit_position = int(bit_position_str) if bit_position_str is not None else None
|
68
|
+
|
69
|
+
return Parameter(
|
70
|
+
oid=oid,
|
71
|
+
byte_position=byte_position,
|
72
|
+
bit_position=bit_position,
|
73
|
+
semantic=semantic,
|
74
|
+
sdgs=sdgs,
|
75
|
+
**kwargs)
|
76
|
+
|
39
77
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
40
78
|
result = {}
|
41
79
|
|
@@ -48,14 +86,14 @@ class Parameter(NamedElement, abc.ABC):
|
|
48
86
|
for sdg in self.sdgs:
|
49
87
|
sdg._resolve_odxlinks(odxlinks)
|
50
88
|
|
51
|
-
def _resolve_snrefs(self,
|
89
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
52
90
|
for sdg in self.sdgs:
|
53
|
-
sdg._resolve_snrefs(
|
91
|
+
sdg._resolve_snrefs(context)
|
54
92
|
|
55
93
|
@property
|
56
|
-
@abc.abstractmethod
|
57
94
|
def parameter_type(self) -> ParameterType:
|
58
|
-
|
95
|
+
raise NotImplementedError(
|
96
|
+
".parameter_type is not implemented by the concrete parameter class")
|
59
97
|
|
60
98
|
def get_static_bit_length(self) -> Optional[int]:
|
61
99
|
return None
|
@@ -70,7 +108,7 @@ class Parameter(NamedElement, abc.ABC):
|
|
70
108
|
specified.
|
71
109
|
|
72
110
|
"""
|
73
|
-
raise NotImplementedError
|
111
|
+
raise NotImplementedError(".is_required is not implemented by the concrete parameter class")
|
74
112
|
|
75
113
|
@property
|
76
114
|
def is_settable(self) -> bool:
|
@@ -81,78 +119,64 @@ class Parameter(NamedElement, abc.ABC):
|
|
81
119
|
have a default value are settable but not required to be
|
82
120
|
specified.
|
83
121
|
"""
|
84
|
-
raise NotImplementedError
|
122
|
+
raise NotImplementedError(".is_settable is not implemented by the concrete parameter class")
|
85
123
|
|
86
|
-
@
|
87
|
-
def
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
124
|
+
@final
|
125
|
+
def encode_into_pdu(self, physical_value: Optional[ParameterValue],
|
126
|
+
encode_state: EncodeState) -> None:
|
127
|
+
"""Convert a physical value into its encoded form and place it
|
128
|
+
into the PDU
|
129
|
+
|
130
|
+
Also, adapt the `encode_state` so that it points to where the
|
131
|
+
next parameter is located (if the next parameter does not
|
132
|
+
explicitly specify a position)
|
92
133
|
|
93
|
-
@abc.abstractmethod
|
94
|
-
def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
95
|
-
"""Decode the parameter value from the coded message.
|
96
|
-
|
97
|
-
If the parameter does have a byte position property, the coded bytes the parameter covers are extracted
|
98
|
-
at this byte position and the function parameter `default_byte_position` is ignored.
|
99
|
-
|
100
|
-
If the parameter does not have a byte position and a byte position is passed,
|
101
|
-
the bytes are extracted at the byte position given by the argument `default_byte_position`.
|
102
|
-
|
103
|
-
If the parameter does not have a byte position and the argument `default_byte_position` is None,
|
104
|
-
this function throws a `DecodeError`.
|
105
|
-
|
106
|
-
Parameters
|
107
|
-
----------
|
108
|
-
decode_state : DecodeState
|
109
|
-
The decoding state containing
|
110
|
-
* the byte message to be decoded
|
111
|
-
* the parameter values that are already decoded
|
112
|
-
* the next byte position that is used iff the parameter does not specify a byte position
|
113
|
-
|
114
|
-
Returns
|
115
|
-
-------
|
116
|
-
ParameterValuePair | List[ParameterValuePair]
|
117
|
-
the decoded parameter value (the type is defined by the DOP)
|
118
|
-
int
|
119
|
-
the next byte position after the extracted parameter
|
120
134
|
"""
|
121
|
-
pass
|
122
135
|
|
123
|
-
|
124
|
-
|
136
|
+
if self.byte_position is not None:
|
137
|
+
encode_state.cursor_byte_position = encode_state.origin_byte_position + self.byte_position
|
138
|
+
|
139
|
+
encode_state.cursor_bit_position = self.bit_position or 0
|
140
|
+
|
141
|
+
self._encode_positioned_into_pdu(physical_value, encode_state)
|
125
142
|
|
126
|
-
|
127
|
-
the byte code is appended to the blob.
|
143
|
+
encode_state.cursor_bit_position = 0
|
128
144
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
into the PDU. Thus it usually suffices to overwrite
|
133
|
-
`get_coded_value_as_bytes()` instead of `encode_into_pdu()`.
|
145
|
+
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
146
|
+
encode_state: EncodeState) -> None:
|
147
|
+
"""Method which actually encodes the parameter
|
134
148
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
149
|
+
Its location is managed by `Parameter`."""
|
150
|
+
raise NotImplementedError(
|
151
|
+
f"Required method '_encode_positioned_into_pdu()' not implemented by "
|
152
|
+
f"child class {type(self).__name__}")
|
153
|
+
|
154
|
+
@final
|
155
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
156
|
+
"""Retrieve the raw data for the parameter from the PDU and
|
157
|
+
convert it to its physical interpretation
|
141
158
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
the message's blob after adding the encoded parameter into it
|
159
|
+
Also, adapt the `encode_state` so that it points to where the
|
160
|
+
next parameter is located (if the next parameter does not
|
161
|
+
explicitly specify a position)
|
146
162
|
|
147
163
|
"""
|
148
|
-
msg_blob = encode_state.coded_message
|
149
|
-
param_blob = self.get_coded_value_as_bytes(encode_state)
|
150
164
|
|
151
165
|
if self.byte_position is not None:
|
152
|
-
|
153
|
-
|
154
|
-
|
166
|
+
decode_state.cursor_byte_position = decode_state.origin_byte_position + self.byte_position
|
167
|
+
|
168
|
+
decode_state.cursor_bit_position = self.bit_position or 0
|
169
|
+
|
170
|
+
result = self._decode_positioned_from_pdu(decode_state)
|
171
|
+
|
172
|
+
decode_state.cursor_bit_position = 0
|
173
|
+
|
174
|
+
return result
|
155
175
|
|
156
|
-
|
176
|
+
def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
177
|
+
"""Method which actually decodes the parameter
|
157
178
|
|
158
|
-
|
179
|
+
Its location is managed by `Parameter`."""
|
180
|
+
raise NotImplementedError(
|
181
|
+
f"Required method '_decode_positioned_from_pdu()' not implemented by "
|
182
|
+
f"child class {type(self).__name__}")
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional, cast
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from typing_extensions import override
|
4
7
|
|
5
8
|
from ..dataobjectproperty import DataObjectProperty
|
6
9
|
from ..decodestate import DecodeState
|
@@ -8,53 +11,65 @@ from ..dopbase import DopBase
|
|
8
11
|
from ..dtcdop import DtcDop
|
9
12
|
from ..encodestate import EncodeState
|
10
13
|
from ..exceptions import odxassert, odxrequire
|
11
|
-
from ..odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
12
|
-
from ..odxtypes import ParameterValue
|
14
|
+
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
15
|
+
from ..odxtypes import AtomicOdxType, ParameterValue
|
13
16
|
from ..physicaltype import PhysicalType
|
17
|
+
from ..snrefcontext import SnRefContext
|
18
|
+
from ..utils import dataclass_fields_asdict
|
14
19
|
from .parameter import Parameter
|
15
20
|
|
16
|
-
if TYPE_CHECKING:
|
17
|
-
from ..diaglayer import DiagLayer
|
18
|
-
|
19
21
|
|
20
22
|
@dataclass
|
21
23
|
class ParameterWithDOP(Parameter):
|
22
24
|
dop_ref: Optional[OdxLinkRef]
|
23
25
|
dop_snref: Optional[str]
|
24
26
|
|
27
|
+
@staticmethod
|
28
|
+
@override
|
29
|
+
def from_et(et_element: ElementTree.Element,
|
30
|
+
doc_frags: List[OdxDocFragment]) -> "ParameterWithDOP":
|
31
|
+
|
32
|
+
kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
|
33
|
+
|
34
|
+
dop_ref = OdxLinkRef.from_et(et_element.find("DOP-REF"), doc_frags)
|
35
|
+
dop_snref = None
|
36
|
+
if (dop_snref_elem := et_element.find("DOP-SNREF")) is not None:
|
37
|
+
dop_snref = odxrequire(dop_snref_elem.get("SHORT-NAME"))
|
38
|
+
|
39
|
+
return ParameterWithDOP(dop_ref=dop_ref, dop_snref=dop_snref, **kwargs)
|
40
|
+
|
25
41
|
def __post_init__(self) -> None:
|
26
42
|
odxassert(self.dop_snref is not None or self.dop_ref is not None,
|
27
43
|
f"Param {self.short_name} without a DOP-(SN)REF should not exist!")
|
28
|
-
self._dop:
|
44
|
+
self._dop: DopBase
|
29
45
|
|
46
|
+
@override
|
30
47
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
31
48
|
return super()._build_odxlinks()
|
32
49
|
|
50
|
+
@override
|
33
51
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
34
52
|
super()._resolve_odxlinks(odxlinks)
|
35
53
|
|
36
54
|
if self.dop_ref is not None:
|
37
55
|
odxassert(self.dop_snref is None)
|
38
|
-
|
39
|
-
# that currently not all kinds of DOPs are internalized
|
40
|
-
# (e.g., static and dynamic fields)
|
41
|
-
self._dop = odxlinks.resolve_lenient(self.dop_ref)
|
56
|
+
self._dop = odxlinks.resolve(self.dop_ref)
|
42
57
|
|
43
|
-
|
44
|
-
|
58
|
+
@override
|
59
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
60
|
+
super()._resolve_snrefs(context)
|
45
61
|
|
46
62
|
if self.dop_snref:
|
47
|
-
ddds = diag_layer.diag_data_dictionary_spec
|
48
|
-
self._dop =
|
63
|
+
ddds = odxrequire(context.diag_layer).diag_data_dictionary_spec
|
64
|
+
self._dop = resolve_snref(self.dop_snref, ddds.all_data_object_properties, DopBase)
|
49
65
|
|
50
66
|
@property
|
51
67
|
def dop(self) -> DopBase:
|
52
|
-
"""
|
68
|
+
"""This is usually a DataObjectProperty or a Structure object"""
|
53
69
|
|
54
|
-
return
|
55
|
-
self._dop, "Specifying a data object property is mandatory but it "
|
56
|
-
"could not be resolved")
|
70
|
+
return self._dop
|
57
71
|
|
72
|
+
@override
|
58
73
|
def get_static_bit_length(self) -> Optional[int]:
|
59
74
|
if self._dop is not None:
|
60
75
|
return self._dop.get_static_bit_length()
|
@@ -68,23 +83,11 @@ class ParameterWithDOP(Parameter):
|
|
68
83
|
else:
|
69
84
|
return None
|
70
85
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
return dop.convert_physical_to_bytes(
|
76
|
-
physical_value, encode_state, bit_position=bit_position_int)
|
77
|
-
|
78
|
-
def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
79
|
-
orig_cursor = decode_state.cursor_byte_position
|
80
|
-
if self.byte_position is not None:
|
81
|
-
decode_state.cursor_byte_position = decode_state.origin_byte_position + self.byte_position
|
82
|
-
|
83
|
-
decode_state.cursor_bit_position = self.bit_position or 0
|
84
|
-
|
85
|
-
# Use DOP to decode
|
86
|
-
phys_val = self.dop.decode_from_pdu(decode_state)
|
87
|
-
|
88
|
-
decode_state.cursor_byte_position = max(orig_cursor, decode_state.cursor_byte_position)
|
86
|
+
@override
|
87
|
+
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
88
|
+
encode_state: EncodeState) -> None:
|
89
|
+
self.dop.encode_into_pdu(cast(AtomicOdxType, physical_value), encode_state)
|
89
90
|
|
90
|
-
|
91
|
+
@override
|
92
|
+
def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
93
|
+
return self.dop.decode_from_pdu(decode_state)
|
@@ -1,37 +1,55 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from typing_extensions import override
|
4
7
|
|
5
8
|
from ..dataobjectproperty import DataObjectProperty
|
6
9
|
from ..decodestate import DecodeState
|
7
10
|
from ..encodestate import EncodeState
|
8
|
-
from ..exceptions import DecodeError, odxraise, odxrequire
|
9
|
-
from ..odxlink import OdxLinkDatabase, OdxLinkId
|
11
|
+
from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
|
12
|
+
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
10
13
|
from ..odxtypes import ParameterValue
|
14
|
+
from ..snrefcontext import SnRefContext
|
15
|
+
from ..utils import dataclass_fields_asdict
|
11
16
|
from .parameter import ParameterType
|
12
17
|
from .parameterwithdop import ParameterWithDOP
|
13
18
|
|
14
|
-
if TYPE_CHECKING:
|
15
|
-
from ..diaglayer import DiagLayer
|
16
|
-
|
17
19
|
|
18
20
|
@dataclass
|
19
21
|
class PhysicalConstantParameter(ParameterWithDOP):
|
20
22
|
|
21
23
|
physical_constant_value_raw: str
|
22
24
|
|
25
|
+
@staticmethod
|
26
|
+
@override
|
27
|
+
def from_et(et_element: ElementTree.Element,
|
28
|
+
doc_frags: List[OdxDocFragment]) -> "PhysicalConstantParameter":
|
29
|
+
|
30
|
+
kwargs = dataclass_fields_asdict(ParameterWithDOP.from_et(et_element, doc_frags))
|
31
|
+
|
32
|
+
physical_constant_value_raw = odxrequire(et_element.findtext("PHYS-CONSTANT-VALUE"))
|
33
|
+
|
34
|
+
return PhysicalConstantParameter(
|
35
|
+
physical_constant_value_raw=physical_constant_value_raw, **kwargs)
|
36
|
+
|
23
37
|
@property
|
38
|
+
@override
|
24
39
|
def parameter_type(self) -> ParameterType:
|
25
40
|
return "PHYS-CONST"
|
26
41
|
|
42
|
+
@override
|
27
43
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
28
44
|
return super()._build_odxlinks()
|
29
45
|
|
46
|
+
@override
|
30
47
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
31
48
|
super()._resolve_odxlinks(odxlinks)
|
32
49
|
|
33
|
-
|
34
|
-
|
50
|
+
@override
|
51
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
52
|
+
super()._resolve_snrefs(context)
|
35
53
|
|
36
54
|
dop = odxrequire(self.dop)
|
37
55
|
if not isinstance(dop, DataObjectProperty):
|
@@ -44,28 +62,30 @@ class PhysicalConstantParameter(ParameterWithDOP):
|
|
44
62
|
return self._physical_constant_value
|
45
63
|
|
46
64
|
@property
|
65
|
+
@override
|
47
66
|
def is_required(self) -> bool:
|
48
67
|
return False
|
49
68
|
|
50
69
|
@property
|
70
|
+
@override
|
51
71
|
def is_settable(self) -> bool:
|
52
72
|
return False
|
53
73
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
f"
|
60
|
-
f"
|
74
|
+
@override
|
75
|
+
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
76
|
+
encode_state: EncodeState) -> None:
|
77
|
+
if physical_value is not None and physical_value != self.physical_constant_value:
|
78
|
+
odxraise(
|
79
|
+
f"Value for constant parameter `{self.short_name}` name can "
|
80
|
+
f"only be specified as {self.physical_constant_value!r} (is: {physical_value!r})",
|
81
|
+
EncodeError)
|
61
82
|
|
62
|
-
|
63
|
-
return dop.convert_physical_to_bytes(
|
64
|
-
self.physical_constant_value, encode_state, bit_position=bit_position_int)
|
83
|
+
self.dop.encode_into_pdu(self.physical_constant_value, encode_state)
|
65
84
|
|
66
|
-
|
85
|
+
@override
|
86
|
+
def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
67
87
|
# Decode value
|
68
|
-
phys_val = super().
|
88
|
+
phys_val = super()._decode_positioned_from_pdu(decode_state)
|
69
89
|
|
70
90
|
# Check if decoded value matches expected value
|
71
91
|
if phys_val != self.physical_constant_value:
|
@@ -75,4 +95,5 @@ class PhysicalConstantParameter(ParameterWithDOP):
|
|
75
95
|
f"{self.physical_constant_value!r} but got {phys_val!r} "
|
76
96
|
f"at byte position {decode_state.cursor_byte_position} "
|
77
97
|
f"in coded message {decode_state.coded_message.hex()}.", DecodeError)
|
98
|
+
|
78
99
|
return phys_val
|