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
odxtools/__init__.py
CHANGED
@@ -62,11 +62,13 @@ References
|
|
62
62
|
- _`[ISO22901]` The ISO 22901 Standard: https://www.iso.org/standard/41207.html
|
63
63
|
|
64
64
|
"""
|
65
|
-
from .
|
66
|
-
from .
|
67
|
-
from .
|
65
|
+
from .loadfile import load_directory as load_directory # noqa: F401
|
66
|
+
from .loadfile import load_file as load_file # noqa: F401
|
67
|
+
from .loadfile import load_files # noqa: F401
|
68
|
+
from .loadfile import load_odx_d_file as load_odx_d_file # noqa: F401
|
69
|
+
from .loadfile import load_pdx_file as load_pdx_file # noqa: F401
|
68
70
|
from .version import __version__ as __version__ # noqa: F401
|
69
|
-
from .
|
71
|
+
from .writepdxfile import write_pdx_file as write_pdx_file # noqa: F401
|
70
72
|
|
71
73
|
__author__ = "Katrin Bauer"
|
72
74
|
|
odxtools/additionalaudience.py
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .element import IdentifiableElement
|
7
7
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
8
|
+
from .snrefcontext import SnRefContext
|
8
9
|
from .utils import dataclass_fields_asdict
|
9
10
|
|
10
|
-
if TYPE_CHECKING:
|
11
|
-
from .diaglayer import DiagLayer
|
12
|
-
|
13
11
|
|
14
12
|
@dataclass
|
15
13
|
class AdditionalAudience(IdentifiableElement):
|
@@ -30,5 +28,5 @@ class AdditionalAudience(IdentifiableElement):
|
|
30
28
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
31
29
|
pass
|
32
30
|
|
33
|
-
def _resolve_snrefs(self,
|
31
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
34
32
|
pass
|
odxtools/admindata.py
CHANGED
@@ -1,14 +1,12 @@
|
|
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 .companydocinfo import CompanyDocInfo
|
7
7
|
from .docrevision import DocRevision
|
8
8
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
9
|
-
|
10
|
-
if TYPE_CHECKING:
|
11
|
-
from .diaglayer import DiagLayer
|
9
|
+
from .snrefcontext import SnRefContext
|
12
10
|
|
13
11
|
|
14
12
|
@dataclass
|
@@ -54,9 +52,9 @@ class AdminData:
|
|
54
52
|
for dr in self.doc_revisions:
|
55
53
|
dr._resolve_odxlinks(odxlinks)
|
56
54
|
|
57
|
-
def _resolve_snrefs(self,
|
55
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
58
56
|
for cdi in self.company_doc_infos:
|
59
|
-
cdi._resolve_snrefs(
|
57
|
+
cdi._resolve_snrefs(context)
|
60
58
|
|
61
59
|
for dr in self.doc_revisions:
|
62
|
-
dr._resolve_snrefs(
|
60
|
+
dr._resolve_snrefs(context)
|
odxtools/audience.py
CHANGED
@@ -1,14 +1,13 @@
|
|
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 .additionalaudience import AdditionalAudience
|
7
|
+
from .nameditemlist import NamedItemList
|
7
8
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
8
9
|
from .odxtypes import odxstr_to_bool
|
9
|
-
|
10
|
-
if TYPE_CHECKING:
|
11
|
-
from .diaglayer import DiagLayer
|
10
|
+
from .snrefcontext import SnRefContext
|
12
11
|
|
13
12
|
|
14
13
|
@dataclass
|
@@ -47,11 +46,11 @@ class Audience:
|
|
47
46
|
return self.is_aftermarket_raw in [None, True]
|
48
47
|
|
49
48
|
@property
|
50
|
-
def enabled_audiences(self) ->
|
49
|
+
def enabled_audiences(self) -> NamedItemList[AdditionalAudience]:
|
51
50
|
return self._enabled_audiences
|
52
51
|
|
53
52
|
@property
|
54
|
-
def disabled_audiences(self) ->
|
53
|
+
def disabled_audiences(self) -> NamedItemList[AdditionalAudience]:
|
55
54
|
return self._disabled_audiences
|
56
55
|
|
57
56
|
@staticmethod
|
@@ -87,12 +86,10 @@ class Audience:
|
|
87
86
|
return {}
|
88
87
|
|
89
88
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
90
|
-
self._enabled_audiences =
|
91
|
-
odxlinks.resolve(ref, AdditionalAudience) for ref in self.enabled_audience_refs
|
92
|
-
|
93
|
-
|
94
|
-
odxlinks.resolve(ref, AdditionalAudience) for ref in self.disabled_audience_refs
|
95
|
-
]
|
89
|
+
self._enabled_audiences = NamedItemList(
|
90
|
+
[odxlinks.resolve(ref, AdditionalAudience) for ref in self.enabled_audience_refs])
|
91
|
+
self._disabled_audiences = NamedItemList(
|
92
|
+
[odxlinks.resolve(ref, AdditionalAudience) for ref in self.disabled_audience_refs])
|
96
93
|
|
97
|
-
def _resolve_snrefs(self,
|
94
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
98
95
|
pass
|
odxtools/basecomparam.py
CHANGED
@@ -1,17 +1,15 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from enum import Enum
|
4
|
-
from typing import
|
4
|
+
from typing import Any, Dict, List, Optional, cast
|
5
5
|
from xml.etree import ElementTree
|
6
6
|
|
7
7
|
from .element import IdentifiableElement
|
8
8
|
from .exceptions import odxraise, odxrequire
|
9
9
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
10
|
+
from .snrefcontext import SnRefContext
|
10
11
|
from .utils import dataclass_fields_asdict
|
11
12
|
|
12
|
-
if TYPE_CHECKING:
|
13
|
-
from .diaglayer import DiagLayer
|
14
|
-
|
15
13
|
|
16
14
|
class StandardizationLevel(Enum):
|
17
15
|
STANDARD = "STANDARD"
|
@@ -74,5 +72,5 @@ class BaseComparam(IdentifiableElement):
|
|
74
72
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
75
73
|
pass
|
76
74
|
|
77
|
-
def _resolve_snrefs(self,
|
75
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
78
76
|
pass
|
odxtools/basicstructure.py
CHANGED
@@ -1,34 +1,34 @@
|
|
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
|
|
6
|
+
from typing_extensions import override
|
7
|
+
|
8
|
+
from .codec import (composite_codec_decode_from_pdu, composite_codec_encode_into_pdu,
|
9
|
+
composite_codec_get_free_parameters, composite_codec_get_required_parameters,
|
10
|
+
composite_codec_get_static_bit_length)
|
7
11
|
from .complexdop import ComplexDop
|
8
|
-
from .dataobjectproperty import DataObjectProperty
|
9
12
|
from .decodestate import DecodeState
|
10
13
|
from .encodestate import EncodeState
|
11
|
-
from .exceptions import DecodeError,
|
14
|
+
from .exceptions import DecodeError, odxraise
|
12
15
|
from .nameditemlist import NamedItemList
|
13
16
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
14
|
-
from .odxtypes import
|
15
|
-
from .parameters.codedconstparameter import CodedConstParameter
|
17
|
+
from .odxtypes import ParameterValue
|
16
18
|
from .parameters.createanyparameter import create_any_parameter_from_et
|
17
|
-
from .parameters.lengthkeyparameter import LengthKeyParameter
|
18
|
-
from .parameters.matchingrequestparameter import MatchingRequestParameter
|
19
|
-
from .parameters.nrcconstparameter import NrcConstParameter
|
20
19
|
from .parameters.parameter import Parameter
|
21
|
-
from .
|
22
|
-
from .parameters.physicalconstantparameter import PhysicalConstantParameter
|
23
|
-
from .parameters.tablekeyparameter import TableKeyParameter
|
20
|
+
from .snrefcontext import SnRefContext
|
24
21
|
from .utils import dataclass_fields_asdict
|
25
22
|
|
26
|
-
if TYPE_CHECKING:
|
27
|
-
from .diaglayer import DiagLayer
|
28
|
-
|
29
23
|
|
30
24
|
@dataclass
|
31
25
|
class BasicStructure(ComplexDop):
|
26
|
+
"""Base class for structure-like objects
|
27
|
+
|
28
|
+
"Structure-like" objects are structures as well as environment
|
29
|
+
data objects. All structure-like objects adhere to the
|
30
|
+
`CompositeCodec` type protocol.
|
31
|
+
"""
|
32
32
|
parameters: NamedItemList[Parameter]
|
33
33
|
byte_size: Optional[int]
|
34
34
|
|
@@ -49,64 +49,20 @@ class BasicStructure(ComplexDop):
|
|
49
49
|
return BasicStructure(parameters=parameters, byte_size=byte_size, **kwargs)
|
50
50
|
|
51
51
|
def get_static_bit_length(self) -> Optional[int]:
|
52
|
-
# Explicit size was specified
|
53
|
-
|
52
|
+
# Explicit size was specified, so we do not need to look at
|
53
|
+
# the list of parameters
|
54
|
+
if self.byte_size is not None:
|
54
55
|
return 8 * self.byte_size
|
55
56
|
|
56
|
-
|
57
|
-
length = 0
|
58
|
-
for param in self.parameters:
|
59
|
-
param_bit_length = param.get_static_bit_length()
|
60
|
-
if param_bit_length is None:
|
61
|
-
# We were not able to calculate a static bit length
|
62
|
-
return None
|
63
|
-
elif param.byte_position is not None:
|
64
|
-
bit_pos = param.bit_position or 0
|
65
|
-
byte_pos = param.byte_position or 0
|
66
|
-
cursor = byte_pos * 8 + bit_pos
|
67
|
-
|
68
|
-
cursor += param_bit_length
|
69
|
-
length = max(length, cursor)
|
70
|
-
|
71
|
-
# Round up to account for padding bits (all structures are
|
72
|
-
# byte aligned)
|
73
|
-
return ((length + 7) // 8) * 8
|
74
|
-
|
75
|
-
def coded_const_prefix(self, request_prefix: bytes = b'') -> bytes:
|
76
|
-
prefix = b''
|
77
|
-
encode_state = EncodeState(
|
78
|
-
bytearray(prefix), parameter_values={}, triggering_request=request_prefix)
|
79
|
-
for param in self.parameters:
|
80
|
-
if isinstance(param, (CodedConstParameter, NrcConstParameter, MatchingRequestParameter,
|
81
|
-
PhysicalConstantParameter)):
|
82
|
-
encode_state.coded_message = bytearray(param.encode_into_pdu(encode_state))
|
83
|
-
else:
|
84
|
-
break
|
85
|
-
return encode_state.coded_message
|
57
|
+
return composite_codec_get_static_bit_length(self)
|
86
58
|
|
87
59
|
@property
|
88
60
|
def required_parameters(self) -> List[Parameter]:
|
89
|
-
|
90
|
-
encoding the structure."""
|
91
|
-
return [p for p in self.parameters if p.is_required]
|
61
|
+
return composite_codec_get_required_parameters(self)
|
92
62
|
|
93
63
|
@property
|
94
64
|
def free_parameters(self) -> List[Parameter]:
|
95
|
-
|
96
|
-
the user when encoding the structure.
|
97
|
-
|
98
|
-
This means all required parameters plus the parameters that
|
99
|
-
can be omitted minus those which are implicitly specified by
|
100
|
-
the corresponding request (in the case of responses).
|
101
|
-
|
102
|
-
"""
|
103
|
-
result: List[Parameter] = []
|
104
|
-
for param in self.parameters:
|
105
|
-
if not param.is_settable:
|
106
|
-
continue
|
107
|
-
result.append(param)
|
108
|
-
|
109
|
-
return result
|
65
|
+
return composite_codec_get_free_parameters(self)
|
110
66
|
|
111
67
|
def print_free_parameters_info(self) -> None:
|
112
68
|
"""Return a human readable description of the structure's
|
@@ -116,186 +72,44 @@ class BasicStructure(ComplexDop):
|
|
116
72
|
|
117
73
|
print(parameter_info(self.free_parameters), end="")
|
118
74
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
if not isinstance(param_value, dict):
|
125
|
-
raise EncodeError(
|
126
|
-
f"Expected a dictionary for the values of structure {self.short_name}, "
|
127
|
-
f"got {type(param_value)}")
|
128
|
-
|
129
|
-
# in strict mode, ensure that no values for unknown parameters are specified.
|
130
|
-
if strict_mode:
|
131
|
-
param_names = [param.short_name for param in self.parameters]
|
132
|
-
for param_key in param_value:
|
133
|
-
if param_key not in param_names:
|
134
|
-
odxraise(f"Value for unknown parameter '{param_key}' specified")
|
135
|
-
|
136
|
-
encode_state = EncodeState(
|
137
|
-
bytearray(),
|
138
|
-
dict(param_value),
|
139
|
-
triggering_request=triggering_coded_request,
|
140
|
-
is_end_of_pdu=False,
|
141
|
-
)
|
142
|
-
|
143
|
-
for param in self.parameters:
|
144
|
-
if param == self.parameters[-1]:
|
145
|
-
# The last parameter is at the end of the PDU if the
|
146
|
-
# structure itself is at the end of the PDU. TODO:
|
147
|
-
# This assumes that the last parameter specified in
|
148
|
-
# the ODX is located last in the PDU...
|
149
|
-
encode_state.is_end_of_pdu = is_end_of_pdu
|
150
|
-
|
151
|
-
if isinstance(
|
152
|
-
param,
|
153
|
-
(LengthKeyParameter, TableKeyParameter)) and param.short_name in param_value:
|
154
|
-
# This is a hack to always encode a dummy value for
|
155
|
-
# length- and table keys. since these can be specified
|
156
|
-
# implicitly (i.e., by means of parameters that use
|
157
|
-
# these keys), to avoid getting an "overlapping
|
158
|
-
# parameter" warning, we must encode a value of zero
|
159
|
-
# into the PDU here and add the real value of the
|
160
|
-
# parameter in a post processing step.
|
161
|
-
tmp = encode_state.parameter_values.pop(param.short_name)
|
162
|
-
encode_state.coded_message = bytearray(param.encode_into_pdu(encode_state))
|
163
|
-
encode_state.parameter_values[param.short_name] = tmp
|
164
|
-
continue
|
165
|
-
|
166
|
-
encode_state.coded_message = bytearray(param.encode_into_pdu(encode_state))
|
167
|
-
|
168
|
-
if self.byte_size is not None and len(encode_state.coded_message) < self.byte_size:
|
169
|
-
# Padding bytes needed
|
170
|
-
encode_state.coded_message = encode_state.coded_message.ljust(self.byte_size, b"\0")
|
171
|
-
|
172
|
-
# encode the length- and table keys. This cannot be done above
|
173
|
-
# because we allow these to be defined implicitly (i.e. they
|
174
|
-
# are defined by their respective users)
|
175
|
-
for param in self.parameters:
|
176
|
-
if not isinstance(param, (LengthKeyParameter, TableKeyParameter)):
|
177
|
-
# the current parameter is neither a length- nor a table key
|
178
|
-
continue
|
179
|
-
|
180
|
-
# Encode the key parameter into the message
|
181
|
-
encode_state.coded_message = bytearray(param.encode_into_pdu(encode_state))
|
182
|
-
|
183
|
-
# Assert that length is as expected
|
184
|
-
self._validate_coded_message(encode_state.coded_message)
|
75
|
+
@override
|
76
|
+
def encode_into_pdu(self, physical_value: Optional[ParameterValue],
|
77
|
+
encode_state: EncodeState) -> None:
|
78
|
+
orig_pos = encode_state.cursor_byte_position
|
185
79
|
|
186
|
-
|
187
|
-
|
188
|
-
def _validate_coded_message(self, coded_message: bytes) -> None:
|
80
|
+
composite_codec_encode_into_pdu(self, physical_value, encode_state)
|
189
81
|
|
190
82
|
if self.byte_size is not None:
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
if len(coded_message) * 8 != bit_length:
|
205
|
-
# We may have broke something
|
206
|
-
# but it could be that bit_length was mis calculated and not the actual bytes are wrong
|
207
|
-
# Could happen with overlapping parameters and parameters with gaps
|
208
|
-
warnings.warn(
|
209
|
-
f"Verification of coded message '{coded_message.hex()}' possibly failed: Size may be incorrect.",
|
210
|
-
OdxWarning,
|
211
|
-
stacklevel=1)
|
212
|
-
|
213
|
-
def convert_physical_to_bytes(self,
|
214
|
-
physical_value: ParameterValue,
|
215
|
-
encode_state: EncodeState,
|
216
|
-
bit_position: int = 0) -> bytes:
|
217
|
-
if not isinstance(physical_value, dict):
|
218
|
-
raise EncodeError(
|
219
|
-
f"Expected a dictionary for the values of structure {self.short_name}, "
|
220
|
-
f"got {type(physical_value)}")
|
221
|
-
if bit_position != 0:
|
222
|
-
raise EncodeError("Structures must be aligned, i.e. bit_position=0, but "
|
223
|
-
f"{self.short_name} was passed the bit position {bit_position}")
|
224
|
-
return self.convert_physical_to_internal(
|
225
|
-
physical_value,
|
226
|
-
triggering_coded_request=encode_state.triggering_request,
|
227
|
-
is_end_of_pdu=encode_state.is_end_of_pdu,
|
228
|
-
)
|
229
|
-
|
83
|
+
actual_len = encode_state.cursor_byte_position - orig_pos
|
84
|
+
|
85
|
+
if actual_len < self.byte_size:
|
86
|
+
# Padding bytes are needed. We add an empty object at
|
87
|
+
# the position directly after the structure and let
|
88
|
+
# EncodeState add the padding as needed.
|
89
|
+
encode_state.cursor_byte_position = encode_state.origin_byte_position + self.byte_size
|
90
|
+
# Padding bytes needed. these count as "used".
|
91
|
+
encode_state.coded_message += b"\x00" * (self.byte_size - actual_len)
|
92
|
+
encode_state.used_mask += b"\xff" * (self.byte_size - actual_len)
|
93
|
+
|
94
|
+
@override
|
230
95
|
def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
231
|
-
|
232
|
-
# structures are relative to the beginning of the structure object.
|
233
|
-
orig_origin = decode_state.origin_byte_position
|
234
|
-
decode_state.origin_byte_position = decode_state.cursor_byte_position
|
96
|
+
orig_pos = decode_state.cursor_byte_position
|
235
97
|
|
236
|
-
result =
|
237
|
-
for param in self.parameters:
|
238
|
-
value = param.decode_from_pdu(decode_state)
|
98
|
+
result = composite_codec_decode_from_pdu(self, decode_state)
|
239
99
|
|
240
|
-
|
100
|
+
if self.byte_size is not None:
|
101
|
+
n = decode_state.cursor_byte_position - orig_pos
|
102
|
+
if n > self.byte_size:
|
103
|
+
odxraise(
|
104
|
+
f"Attempted to decode too large instance of structure "
|
105
|
+
f"{self.short_name} ({n} instead at most "
|
106
|
+
f"{self.byte_size} bytes)", DecodeError)
|
107
|
+
return result
|
241
108
|
|
242
|
-
|
243
|
-
decode_state.origin_byte_position = orig_origin
|
109
|
+
decode_state.cursor_byte_position = orig_pos + self.byte_size
|
244
110
|
|
245
111
|
return result
|
246
112
|
|
247
|
-
def encode(self, coded_request: Optional[bytes] = None, **params: ParameterValue) -> bytes:
|
248
|
-
"""
|
249
|
-
Composes an UDS message as bytes for this service.
|
250
|
-
Parameters:
|
251
|
-
----------
|
252
|
-
coded_request: bytes
|
253
|
-
coded request (only needed when encoding a response)
|
254
|
-
params: dict
|
255
|
-
Parameters of the RPC as mapping from SHORT-NAME of the parameter to the value
|
256
|
-
"""
|
257
|
-
return self.convert_physical_to_internal(
|
258
|
-
params, triggering_coded_request=coded_request, is_end_of_pdu=True)
|
259
|
-
|
260
|
-
def decode(self, message: bytes) -> ParameterValueDict:
|
261
|
-
decode_state = DecodeState(coded_message=message)
|
262
|
-
param_values = self.decode_from_pdu(decode_state)
|
263
|
-
|
264
|
-
if len(message) != decode_state.cursor_byte_position:
|
265
|
-
odxraise(
|
266
|
-
f"The message {message.hex()} probably could not be completely parsed:"
|
267
|
-
f" Expected length of {decode_state.cursor_byte_position} but got {len(message)}.",
|
268
|
-
DecodeError)
|
269
|
-
return {}
|
270
|
-
|
271
|
-
if not isinstance(param_values, dict):
|
272
|
-
odxraise("Decoding structures must result in a dictionary")
|
273
|
-
|
274
|
-
return cast(ParameterValueDict, param_values)
|
275
|
-
|
276
|
-
def parameter_dict(self) -> ParameterDict:
|
277
|
-
"""
|
278
|
-
Returns a dictionary with all parameter short names as keys.
|
279
|
-
|
280
|
-
The values are parameters for simple types or a nested dict for structures.
|
281
|
-
"""
|
282
|
-
from .structure import Structure
|
283
|
-
odxassert(
|
284
|
-
all(not isinstance(p, ParameterWithDOP) or isinstance(p.dop, DataObjectProperty) or
|
285
|
-
isinstance(p.dop, Structure) for p in self.parameters))
|
286
|
-
param_dict: ParameterDict = {
|
287
|
-
p.short_name: p
|
288
|
-
for p in self.parameters
|
289
|
-
if not isinstance(p, ParameterWithDOP) or not isinstance(p.dop, Structure)
|
290
|
-
}
|
291
|
-
param_dict.update({
|
292
|
-
struct_param.short_name: struct_param.dop.parameter_dict()
|
293
|
-
for struct_param in self.parameters
|
294
|
-
if isinstance(struct_param, ParameterWithDOP) and
|
295
|
-
isinstance(struct_param.dop, BasicStructure)
|
296
|
-
})
|
297
|
-
return param_dict
|
298
|
-
|
299
113
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
300
114
|
result = super()._build_odxlinks()
|
301
115
|
|
@@ -305,15 +119,16 @@ class BasicStructure(ComplexDop):
|
|
305
119
|
return result
|
306
120
|
|
307
121
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
308
|
-
"""Recursively resolve any references (odxlinks or sn-refs)"""
|
309
122
|
super()._resolve_odxlinks(odxlinks)
|
310
123
|
|
311
124
|
for param in self.parameters:
|
312
125
|
param._resolve_odxlinks(odxlinks)
|
313
126
|
|
314
|
-
def _resolve_snrefs(self,
|
315
|
-
|
316
|
-
super()._resolve_snrefs(diag_layer)
|
127
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
128
|
+
context.parameters = self.parameters
|
317
129
|
|
130
|
+
super()._resolve_snrefs(context)
|
318
131
|
for param in self.parameters:
|
319
|
-
param._resolve_snrefs(
|
132
|
+
param._resolve_snrefs(context)
|
133
|
+
|
134
|
+
context.parameters = None
|
odxtools/cli/_parser_utils.py
CHANGED