odxtools 6.7.0__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 +6 -4
- odxtools/additionalaudience.py +3 -5
- odxtools/admindata.py +5 -7
- odxtools/audience.py +10 -13
- odxtools/basecomparam.py +3 -5
- odxtools/basicstructure.py +55 -240
- odxtools/cli/_parser_utils.py +1 -1
- odxtools/cli/_print_utils.py +168 -134
- odxtools/cli/browse.py +111 -92
- odxtools/cli/compare.py +90 -71
- odxtools/cli/list.py +24 -15
- odxtools/cli/snoop.py +28 -5
- 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 +7 -9
- 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 +93 -12
- odxtools/compumethods/compuphystointernal.py +56 -0
- odxtools/compumethods/compurationalcoeffs.py +20 -9
- odxtools/compumethods/compuscale.py +30 -35
- odxtools/compumethods/createanycompumethod.py +28 -161
- odxtools/compumethods/identicalcompumethod.py +31 -6
- odxtools/compumethods/linearcompumethod.py +69 -189
- 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 +119 -99
- odxtools/compumethods/texttablecompumethod.py +107 -43
- odxtools/createanydiagcodedtype.py +10 -67
- odxtools/database.py +167 -87
- odxtools/dataobjectproperty.py +15 -25
- odxtools/decodestate.py +9 -15
- odxtools/description.py +47 -0
- odxtools/determinenumberofitems.py +4 -5
- odxtools/diagcodedtype.py +36 -106
- odxtools/diagcomm.py +24 -12
- odxtools/diagdatadictionaryspec.py +33 -34
- 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/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} +209 -448
- 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 +56 -43
- odxtools/diagvariable.py +113 -0
- odxtools/docrevision.py +5 -7
- odxtools/dopbase.py +15 -17
- odxtools/dtcdop.py +168 -50
- odxtools/dynamicendmarkerfield.py +134 -0
- odxtools/dynamiclengthfield.py +41 -37
- 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 -38
- odxtools/exceptions.py +11 -2
- odxtools/field.py +10 -10
- odxtools/functionalclass.py +3 -5
- odxtools/inputparam.py +3 -12
- 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 +128 -73
- odxtools/multiplexercase.py +13 -14
- odxtools/multiplexerdefaultcase.py +15 -12
- odxtools/multiplexerswitchkey.py +4 -5
- odxtools/nameditemlist.py +29 -5
- odxtools/negoutputparam.py +3 -5
- odxtools/odxcategory.py +83 -0
- odxtools/odxlink.py +60 -51
- odxtools/odxtypes.py +37 -5
- odxtools/outputparam.py +4 -15
- odxtools/parameterinfo.py +218 -67
- odxtools/parameters/codedconstparameter.py +16 -24
- odxtools/parameters/dynamicparameter.py +5 -4
- odxtools/parameters/lengthkeyparameter.py +60 -26
- odxtools/parameters/matchingrequestparameter.py +23 -11
- odxtools/parameters/nrcconstparameter.py +45 -46
- odxtools/parameters/parameter.py +54 -56
- odxtools/parameters/parameterwithdop.py +15 -25
- odxtools/parameters/physicalconstantparameter.py +15 -18
- odxtools/parameters/reservedparameter.py +6 -2
- odxtools/parameters/systemparameter.py +55 -11
- odxtools/parameters/tableentryparameter.py +3 -2
- odxtools/parameters/tablekeyparameter.py +103 -49
- odxtools/parameters/tablestructparameter.py +47 -48
- odxtools/parameters/valueparameter.py +16 -20
- odxtools/paramlengthinfotype.py +52 -32
- odxtools/parentref.py +16 -2
- 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 +3 -3
- 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 +7 -17
- odxtools/staticfield.py +31 -25
- odxtools/subcomponent.py +288 -0
- odxtools/swvariable.py +21 -0
- odxtools/table.py +7 -8
- odxtools/tablerow.py +19 -11
- 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 -133
- 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 +4 -3
- odxtools/templates/macros/printOdxCategory.xml.jinja2 +28 -0
- odxtools/templates/macros/printParam.xml.jinja2 +11 -12
- 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 +1 -1
- 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} +20 -10
- odxtools/xdoc.py +3 -5
- {odxtools-6.7.0.dist-info → odxtools-9.3.0.dist-info}/METADATA +20 -21
- odxtools-9.3.0.dist-info/RECORD +228 -0
- {odxtools-6.7.0.dist-info → odxtools-9.3.0.dist-info}/WHEEL +1 -1
- odxtools/createcompanydatas.py +0 -17
- odxtools/createsdgs.py +0 -19
- 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 -216
- odxtools-6.7.0.dist-info/RECORD +0 -182
- /odxtools/{diaglayertype.py → diaglayers/diaglayertype.py} +0 -0
- {odxtools-6.7.0.dist-info → odxtools-9.3.0.dist-info}/LICENSE +0 -0
- {odxtools-6.7.0.dist-info → odxtools-9.3.0.dist-info}/entry_points.txt +0 -0
- {odxtools-6.7.0.dist-info → odxtools-9.3.0.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,6 @@
|
|
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
|
5
4
|
from xml.etree import ElementTree
|
6
5
|
|
7
6
|
from typing_extensions import override
|
@@ -10,25 +9,29 @@ from ..createanydiagcodedtype import create_any_diag_coded_type_from_et
|
|
10
9
|
from ..decodestate import DecodeState
|
11
10
|
from ..diagcodedtype import DiagCodedType
|
12
11
|
from ..encodestate import EncodeState
|
13
|
-
from ..exceptions import
|
14
|
-
from ..odxlink import OdxDocFragment,
|
15
|
-
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
|
16
15
|
from ..utils import dataclass_fields_asdict
|
17
16
|
from .parameter import Parameter, ParameterType
|
18
17
|
|
19
|
-
if TYPE_CHECKING:
|
20
|
-
from ..diaglayer import DiagLayer
|
21
|
-
|
22
18
|
|
23
19
|
@dataclass
|
24
20
|
class NrcConstParameter(Parameter):
|
25
|
-
"""A
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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.
|
30
32
|
|
31
33
|
See ASAM MCD-2 D (ODX), p. 77-79.
|
34
|
+
|
32
35
|
"""
|
33
36
|
|
34
37
|
diag_coded_type: DiagCodedType
|
@@ -64,14 +67,6 @@ class NrcConstParameter(Parameter):
|
|
64
67
|
|
65
68
|
return result
|
66
69
|
|
67
|
-
@override
|
68
|
-
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
69
|
-
super()._resolve_odxlinks(odxlinks)
|
70
|
-
|
71
|
-
@override
|
72
|
-
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
73
|
-
super()._resolve_snrefs(diag_layer)
|
74
|
-
|
75
70
|
@override
|
76
71
|
def get_static_bit_length(self) -> Optional[int]:
|
77
72
|
return self.diag_coded_type.get_static_bit_length()
|
@@ -91,38 +86,42 @@ class NrcConstParameter(Parameter):
|
|
91
86
|
return False
|
92
87
|
|
93
88
|
@override
|
94
|
-
def
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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)
|
109
116
|
|
110
117
|
@override
|
111
118
|
def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> AtomicOdxType:
|
112
|
-
# Extract coded
|
119
|
+
# Extract coded value
|
113
120
|
coded_value = self.diag_coded_type.decode_from_pdu(decode_state)
|
114
121
|
|
115
122
|
# Check if the coded value in the message is correct.
|
116
123
|
if coded_value not in self.coded_values:
|
117
|
-
|
118
|
-
f"Coded constant parameter does not match! "
|
119
|
-
f"The parameter {self.short_name} expected a coded "
|
120
|
-
f"value in {str(self.coded_values)} but got {str(coded_value)} "
|
121
|
-
f"at byte position {decode_state.cursor_byte_position} "
|
122
|
-
f"in coded message {decode_state.coded_message.hex()}.",
|
123
|
-
DecodeError,
|
124
|
-
stacklevel=1,
|
125
|
-
)
|
124
|
+
raise DecodeMismatch(f"NRC-CONST parameter {self.short_name} does not apply")
|
126
125
|
|
127
126
|
return coded_value
|
128
127
|
|
odxtools/parameters/parameter.py
CHANGED
@@ -1,22 +1,19 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Literal, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from typing_extensions import final, override
|
7
7
|
|
8
|
-
from ..createsdgs import create_sdgs_from_et
|
9
8
|
from ..decodestate import DecodeState
|
10
9
|
from ..element import NamedElement
|
11
10
|
from ..encodestate import EncodeState
|
12
11
|
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
13
12
|
from ..odxtypes import ParameterValue
|
13
|
+
from ..snrefcontext import SnRefContext
|
14
14
|
from ..specialdatagroup import SpecialDataGroup
|
15
15
|
from ..utils import dataclass_fields_asdict
|
16
16
|
|
17
|
-
if TYPE_CHECKING:
|
18
|
-
from ..diaglayer import DiagLayer
|
19
|
-
|
20
17
|
ParameterType = Literal[
|
21
18
|
"CODED-CONST",
|
22
19
|
"DYNAMIC",
|
@@ -36,13 +33,16 @@ ParameterType = Literal[
|
|
36
33
|
@dataclass
|
37
34
|
class Parameter(NamedElement):
|
38
35
|
"""This class corresponds to POSITIONABLE-PARAM in the ODX
|
39
|
-
specification
|
36
|
+
specification
|
40
37
|
|
41
|
-
|
42
|
-
|
43
|
-
|
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.
|
44
43
|
|
45
44
|
"""
|
45
|
+
oid: Optional[str]
|
46
46
|
byte_position: Optional[int]
|
47
47
|
bit_position: Optional[int]
|
48
48
|
semantic: Optional[str]
|
@@ -54,8 +54,11 @@ class Parameter(NamedElement):
|
|
54
54
|
|
55
55
|
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
|
56
56
|
|
57
|
+
oid = et_element.get("OID")
|
57
58
|
semantic = et_element.get("SEMANTIC")
|
58
|
-
sdgs =
|
59
|
+
sdgs = [
|
60
|
+
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
61
|
+
]
|
59
62
|
|
60
63
|
byte_position_str = et_element.findtext("BYTE-POSITION")
|
61
64
|
bit_position_str = et_element.findtext("BIT-POSITION")
|
@@ -64,6 +67,7 @@ class Parameter(NamedElement):
|
|
64
67
|
bit_position = int(bit_position_str) if bit_position_str is not None else None
|
65
68
|
|
66
69
|
return Parameter(
|
70
|
+
oid=oid,
|
67
71
|
byte_position=byte_position,
|
68
72
|
bit_position=bit_position,
|
69
73
|
semantic=semantic,
|
@@ -82,9 +86,9 @@ class Parameter(NamedElement):
|
|
82
86
|
for sdg in self.sdgs:
|
83
87
|
sdg._resolve_odxlinks(odxlinks)
|
84
88
|
|
85
|
-
def _resolve_snrefs(self,
|
89
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
86
90
|
for sdg in self.sdgs:
|
87
|
-
sdg._resolve_snrefs(
|
91
|
+
sdg._resolve_snrefs(context)
|
88
92
|
|
89
93
|
@property
|
90
94
|
def parameter_type(self) -> ParameterType:
|
@@ -117,16 +121,47 @@ class Parameter(NamedElement):
|
|
117
121
|
"""
|
118
122
|
raise NotImplementedError(".is_settable is not implemented by the concrete parameter class")
|
119
123
|
|
120
|
-
|
121
|
-
|
122
|
-
|
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)
|
133
|
+
|
123
134
|
"""
|
135
|
+
|
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)
|
142
|
+
|
143
|
+
encode_state.cursor_bit_position = 0
|
144
|
+
|
145
|
+
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
146
|
+
encode_state: EncodeState) -> None:
|
147
|
+
"""Method which actually encodes the parameter
|
148
|
+
|
149
|
+
Its location is managed by `Parameter`."""
|
124
150
|
raise NotImplementedError(
|
125
|
-
"
|
151
|
+
f"Required method '_encode_positioned_into_pdu()' not implemented by "
|
152
|
+
f"child class {type(self).__name__}")
|
126
153
|
|
127
154
|
@final
|
128
155
|
def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
129
|
-
|
156
|
+
"""Retrieve the raw data for the parameter from the PDU and
|
157
|
+
convert it to its physical interpretation
|
158
|
+
|
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)
|
162
|
+
|
163
|
+
"""
|
164
|
+
|
130
165
|
if self.byte_position is not None:
|
131
166
|
decode_state.cursor_byte_position = decode_state.origin_byte_position + self.byte_position
|
132
167
|
|
@@ -134,7 +169,6 @@ class Parameter(NamedElement):
|
|
134
169
|
|
135
170
|
result = self._decode_positioned_from_pdu(decode_state)
|
136
171
|
|
137
|
-
decode_state.cursor_byte_position = max(decode_state.cursor_byte_position, orig_cursor)
|
138
172
|
decode_state.cursor_bit_position = 0
|
139
173
|
|
140
174
|
return result
|
@@ -144,41 +178,5 @@ class Parameter(NamedElement):
|
|
144
178
|
|
145
179
|
Its location is managed by `Parameter`."""
|
146
180
|
raise NotImplementedError(
|
147
|
-
"Required method '_decode_positioned_from_pdu()' not implemented by
|
148
|
-
|
149
|
-
def encode_into_pdu(self, encode_state: EncodeState) -> bytes:
|
150
|
-
"""Encode the value of a parameter into a binary blob and return it
|
151
|
-
|
152
|
-
If the byte position of the parameter is not defined,
|
153
|
-
the byte code is appended to the blob.
|
154
|
-
|
155
|
-
Technical note for subclasses: The default implementation
|
156
|
-
tries to compute the coded value via
|
157
|
-
`self.get_coded_value_as_bytes(encoded_state)` and inserts it
|
158
|
-
into the PDU. Thus it usually suffices to overwrite
|
159
|
-
`get_coded_value_as_bytes()` instead of `encode_into_pdu()`.
|
160
|
-
|
161
|
-
Parameters:
|
162
|
-
----------
|
163
|
-
encode_state: EncodeState, i.e. a named tuple with attributes
|
164
|
-
* coded_message: bytes, the message encoded so far
|
165
|
-
* parameter_values: List[ParameterValuePairs]
|
166
|
-
* triggering_coded_request: bytes
|
167
|
-
|
168
|
-
Returns:
|
169
|
-
-------
|
170
|
-
bytes
|
171
|
-
the message's blob after adding the encoded parameter into it
|
172
|
-
|
173
|
-
"""
|
174
|
-
msg_blob = encode_state.coded_message
|
175
|
-
param_blob = self.get_coded_value_as_bytes(encode_state)
|
176
|
-
|
177
|
-
if self.byte_position is not None:
|
178
|
-
byte_position = self.byte_position
|
179
|
-
else:
|
180
|
-
byte_position = len(msg_blob)
|
181
|
-
|
182
|
-
encode_state.emplace_atomic_value(param_blob, self.short_name, byte_position)
|
183
|
-
|
184
|
-
return encode_state.coded_message
|
181
|
+
f"Required method '_decode_positioned_from_pdu()' not implemented by "
|
182
|
+
f"child class {type(self).__name__}")
|
@@ -1,6 +1,6 @@
|
|
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
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from typing_extensions import override
|
@@ -11,15 +11,13 @@ from ..dopbase import DopBase
|
|
11
11
|
from ..dtcdop import DtcDop
|
12
12
|
from ..encodestate import EncodeState
|
13
13
|
from ..exceptions import odxassert, odxrequire
|
14
|
-
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
15
|
-
from ..odxtypes import ParameterValue
|
14
|
+
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
15
|
+
from ..odxtypes import AtomicOdxType, ParameterValue
|
16
16
|
from ..physicaltype import PhysicalType
|
17
|
+
from ..snrefcontext import SnRefContext
|
17
18
|
from ..utils import dataclass_fields_asdict
|
18
19
|
from .parameter import Parameter
|
19
20
|
|
20
|
-
if TYPE_CHECKING:
|
21
|
-
from ..diaglayer import DiagLayer
|
22
|
-
|
23
21
|
|
24
22
|
@dataclass
|
25
23
|
class ParameterWithDOP(Parameter):
|
@@ -43,7 +41,7 @@ class ParameterWithDOP(Parameter):
|
|
43
41
|
def __post_init__(self) -> None:
|
44
42
|
odxassert(self.dop_snref is not None or self.dop_ref is not None,
|
45
43
|
f"Param {self.short_name} without a DOP-(SN)REF should not exist!")
|
46
|
-
self._dop:
|
44
|
+
self._dop: DopBase
|
47
45
|
|
48
46
|
@override
|
49
47
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
@@ -55,26 +53,21 @@ class ParameterWithDOP(Parameter):
|
|
55
53
|
|
56
54
|
if self.dop_ref is not None:
|
57
55
|
odxassert(self.dop_snref is None)
|
58
|
-
|
59
|
-
# that currently not all kinds of DOPs are internalized
|
60
|
-
# (e.g., static and dynamic fields)
|
61
|
-
self._dop = odxlinks.resolve_lenient(self.dop_ref)
|
56
|
+
self._dop = odxlinks.resolve(self.dop_ref)
|
62
57
|
|
63
58
|
@override
|
64
|
-
def _resolve_snrefs(self,
|
65
|
-
super()._resolve_snrefs(
|
59
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
60
|
+
super()._resolve_snrefs(context)
|
66
61
|
|
67
62
|
if self.dop_snref:
|
68
|
-
ddds = diag_layer.diag_data_dictionary_spec
|
69
|
-
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)
|
70
65
|
|
71
66
|
@property
|
72
67
|
def dop(self) -> DopBase:
|
73
|
-
"""
|
68
|
+
"""This is usually a DataObjectProperty or a Structure object"""
|
74
69
|
|
75
|
-
return
|
76
|
-
self._dop, "Specifying a data object property is mandatory but it "
|
77
|
-
"could not be resolved")
|
70
|
+
return self._dop
|
78
71
|
|
79
72
|
@override
|
80
73
|
def get_static_bit_length(self) -> Optional[int]:
|
@@ -91,12 +84,9 @@ class ParameterWithDOP(Parameter):
|
|
91
84
|
return None
|
92
85
|
|
93
86
|
@override
|
94
|
-
def
|
95
|
-
|
96
|
-
physical_value
|
97
|
-
bit_position_int = self.bit_position if self.bit_position is not None else 0
|
98
|
-
return dop.convert_physical_to_bytes(
|
99
|
-
physical_value, encode_state, bit_position=bit_position_int)
|
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)
|
100
90
|
|
101
91
|
@override
|
102
92
|
def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
@@ -1,6 +1,6 @@
|
|
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
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from typing_extensions import override
|
@@ -8,16 +8,14 @@ from typing_extensions import override
|
|
8
8
|
from ..dataobjectproperty import DataObjectProperty
|
9
9
|
from ..decodestate import DecodeState
|
10
10
|
from ..encodestate import EncodeState
|
11
|
-
from ..exceptions import DecodeError, odxraise, odxrequire
|
11
|
+
from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
|
12
12
|
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
13
13
|
from ..odxtypes import ParameterValue
|
14
|
+
from ..snrefcontext import SnRefContext
|
14
15
|
from ..utils import dataclass_fields_asdict
|
15
16
|
from .parameter import ParameterType
|
16
17
|
from .parameterwithdop import ParameterWithDOP
|
17
18
|
|
18
|
-
if TYPE_CHECKING:
|
19
|
-
from ..diaglayer import DiagLayer
|
20
|
-
|
21
19
|
|
22
20
|
@dataclass
|
23
21
|
class PhysicalConstantParameter(ParameterWithDOP):
|
@@ -50,8 +48,8 @@ class PhysicalConstantParameter(ParameterWithDOP):
|
|
50
48
|
super()._resolve_odxlinks(odxlinks)
|
51
49
|
|
52
50
|
@override
|
53
|
-
def _resolve_snrefs(self,
|
54
|
-
super()._resolve_snrefs(
|
51
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
52
|
+
super()._resolve_snrefs(context)
|
55
53
|
|
56
54
|
dop = odxrequire(self.dop)
|
57
55
|
if not isinstance(dop, DataObjectProperty):
|
@@ -74,17 +72,15 @@ class PhysicalConstantParameter(ParameterWithDOP):
|
|
74
72
|
return False
|
75
73
|
|
76
74
|
@override
|
77
|
-
def
|
78
|
-
|
79
|
-
if
|
80
|
-
|
81
|
-
|
82
|
-
f"
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
return dop.convert_physical_to_bytes(
|
87
|
-
self.physical_constant_value, encode_state, bit_position=bit_position_int)
|
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)
|
82
|
+
|
83
|
+
self.dop.encode_into_pdu(self.physical_constant_value, encode_state)
|
88
84
|
|
89
85
|
@override
|
90
86
|
def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
@@ -99,4 +95,5 @@ class PhysicalConstantParameter(ParameterWithDOP):
|
|
99
95
|
f"{self.physical_constant_value!r} but got {phys_val!r} "
|
100
96
|
f"at byte position {decode_state.cursor_byte_position} "
|
101
97
|
f"in coded message {decode_state.coded_message.hex()}.", DecodeError)
|
98
|
+
|
102
99
|
return phys_val
|
@@ -49,8 +49,12 @@ class ReservedParameter(Parameter):
|
|
49
49
|
return self.bit_length
|
50
50
|
|
51
51
|
@override
|
52
|
-
def
|
53
|
-
|
52
|
+
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
53
|
+
encode_state: EncodeState) -> None:
|
54
|
+
encode_state.cursor_byte_position += (encode_state.cursor_bit_position + self.bit_length +
|
55
|
+
7) // 8
|
56
|
+
encode_state.cursor_bit_position = 0
|
57
|
+
encode_state.emplace_bytes(b'', self.short_name)
|
54
58
|
|
55
59
|
@override
|
56
60
|
def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
@@ -1,19 +1,29 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
+
import getpass
|
2
3
|
from dataclasses import dataclass
|
3
|
-
from
|
4
|
+
from datetime import datetime
|
5
|
+
from typing import List, Optional
|
4
6
|
from xml.etree import ElementTree
|
5
7
|
|
6
8
|
from typing_extensions import override
|
7
9
|
|
8
|
-
from ..decodestate import DecodeState
|
9
10
|
from ..encodestate import EncodeState
|
10
|
-
from ..exceptions import odxrequire
|
11
|
+
from ..exceptions import odxraise, odxrequire
|
11
12
|
from ..odxlink import OdxDocFragment
|
12
13
|
from ..odxtypes import ParameterValue
|
13
14
|
from ..utils import dataclass_fields_asdict
|
14
15
|
from .parameter import ParameterType
|
15
16
|
from .parameterwithdop import ParameterWithDOP
|
16
17
|
|
18
|
+
# The SYSTEM parameter types mandated by the ODX 2.2 standard. Users
|
19
|
+
# are free to specify additional types, but these must be handled
|
20
|
+
# (cf. table 5 in section 7.3.5.4 of the ASAM ODX 2.2 specification
|
21
|
+
# document.)
|
22
|
+
PREDEFINED_SYSPARAM_VALUES = [
|
23
|
+
"TIMESTAMP", "SECOND", "MINUTE", "HOUR", "TIMEZONE", "DAY", "WEEK", "MONTH", "YEAR", "CENTURY",
|
24
|
+
"TESTERID", "USERID"
|
25
|
+
]
|
26
|
+
|
17
27
|
|
18
28
|
@dataclass
|
19
29
|
class SystemParameter(ParameterWithDOP):
|
@@ -26,7 +36,7 @@ class SystemParameter(ParameterWithDOP):
|
|
26
36
|
|
27
37
|
kwargs = dataclass_fields_asdict(ParameterWithDOP.from_et(et_element, doc_frags))
|
28
38
|
|
29
|
-
sysparam = odxrequire(et_element.
|
39
|
+
sysparam = odxrequire(et_element.get("SYSPARAM"))
|
30
40
|
|
31
41
|
return SystemParameter(sysparam=sysparam, **kwargs)
|
32
42
|
|
@@ -38,17 +48,51 @@ class SystemParameter(ParameterWithDOP):
|
|
38
48
|
@property
|
39
49
|
@override
|
40
50
|
def is_required(self) -> bool:
|
41
|
-
|
51
|
+
# if a SYSTEM parameter is not specified explicitly, its value
|
52
|
+
# can be determined from the operating system if it is type is
|
53
|
+
# predefined
|
54
|
+
return self.sysparam not in PREDEFINED_SYSPARAM_VALUES
|
42
55
|
|
43
56
|
@property
|
44
57
|
@override
|
45
58
|
def is_settable(self) -> bool:
|
46
|
-
|
59
|
+
return True
|
47
60
|
|
48
61
|
@override
|
49
|
-
def
|
50
|
-
|
62
|
+
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
63
|
+
encode_state: EncodeState) -> None:
|
64
|
+
if physical_value is None:
|
65
|
+
# determine the value to be encoded automatically
|
66
|
+
now = datetime.now()
|
67
|
+
if self.sysparam == "TIMESTAMP":
|
68
|
+
physical_value = round(now.timestamp() * 1000).to_bytes(8, "big")
|
69
|
+
elif self.sysparam == "SECOND":
|
70
|
+
physical_value = now.second
|
71
|
+
elif self.sysparam == "MINUTE":
|
72
|
+
physical_value = now.minute
|
73
|
+
elif self.sysparam == "HOUR":
|
74
|
+
physical_value = now.hour
|
75
|
+
elif self.sysparam == "TIMEZONE":
|
76
|
+
if (utc_offset := now.astimezone().utcoffset()) is not None:
|
77
|
+
physical_value = utc_offset.seconds // 60
|
78
|
+
else:
|
79
|
+
physical_value = 0
|
80
|
+
elif self.sysparam == "DAY":
|
81
|
+
physical_value = now.day
|
82
|
+
elif self.sysparam == "WEEK":
|
83
|
+
physical_value = now.isocalendar()[1]
|
84
|
+
elif self.sysparam == "MONTH":
|
85
|
+
physical_value = now.month
|
86
|
+
elif self.sysparam == "YEAR":
|
87
|
+
physical_value = now.year
|
88
|
+
elif self.sysparam == "CENTURY":
|
89
|
+
physical_value = now.year // 100
|
90
|
+
elif self.sysparam == "TESTERID":
|
91
|
+
physical_value = "odxtools".encode("latin1")
|
92
|
+
elif self.sysparam == "USERID":
|
93
|
+
physical_value = getpass.getuser().encode("latin1")
|
94
|
+
else:
|
95
|
+
odxraise(f"Unknown system parameter type '{self.sysparam}'")
|
96
|
+
physical_value = 0
|
51
97
|
|
52
|
-
|
53
|
-
def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
54
|
-
raise NotImplementedError("Decoding SystemParameter is not implemented yet.")
|
98
|
+
self.dop.encode_into_pdu(physical_value, encode_state=encode_state)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import TYPE_CHECKING, List
|
3
|
+
from typing import TYPE_CHECKING, List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from typing_extensions import override
|
@@ -59,7 +59,8 @@ class TableEntryParameter(Parameter):
|
|
59
59
|
raise NotImplementedError("TableEntryParameter.is_settable is not implemented yet.")
|
60
60
|
|
61
61
|
@override
|
62
|
-
def
|
62
|
+
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
63
|
+
encode_state: EncodeState) -> None:
|
63
64
|
raise NotImplementedError("Encoding a TableEntryParameter is not implemented yet.")
|
64
65
|
|
65
66
|
@property
|