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
odxtools/relateddoc.py
CHANGED
@@ -1,24 +1,22 @@
|
|
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
|
+
from .description import Description
|
6
7
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
7
|
-
from .
|
8
|
+
from .snrefcontext import SnRefContext
|
8
9
|
from .xdoc import XDoc
|
9
10
|
|
10
|
-
if TYPE_CHECKING:
|
11
|
-
from .diaglayer import DiagLayer
|
12
|
-
|
13
11
|
|
14
12
|
@dataclass
|
15
13
|
class RelatedDoc:
|
16
|
-
description: Optional[
|
14
|
+
description: Optional[Description]
|
17
15
|
xdoc: Optional[XDoc]
|
18
16
|
|
19
17
|
@staticmethod
|
20
18
|
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "RelatedDoc":
|
21
|
-
description =
|
19
|
+
description = Description.from_et(et_element.find("DESC"), doc_frags)
|
22
20
|
|
23
21
|
xdoc: Optional[XDoc] = None
|
24
22
|
if (xdoc_elem := et_element.find("XDOC")) is not None:
|
@@ -41,6 +39,6 @@ class RelatedDoc:
|
|
41
39
|
if self.xdoc:
|
42
40
|
self.xdoc._resolve_odxlinks(odxlinks)
|
43
41
|
|
44
|
-
def _resolve_snrefs(self,
|
42
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
45
43
|
if self.xdoc:
|
46
|
-
self.xdoc._resolve_snrefs(
|
44
|
+
self.xdoc._resolve_snrefs(context)
|
odxtools/request.py
CHANGED
@@ -1,22 +1,132 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import List
|
3
|
+
from typing import Any, Dict, List, Optional, cast
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
-
from .
|
7
|
-
from .
|
6
|
+
from .admindata import AdminData
|
7
|
+
from .codec import (composite_codec_decode_from_pdu, composite_codec_encode_into_pdu,
|
8
|
+
composite_codec_get_coded_const_prefix, composite_codec_get_free_parameters,
|
9
|
+
composite_codec_get_required_parameters, composite_codec_get_static_bit_length)
|
10
|
+
from .decodestate import DecodeState
|
11
|
+
from .element import IdentifiableElement
|
12
|
+
from .encodestate import EncodeState
|
13
|
+
from .exceptions import odxraise
|
14
|
+
from .nameditemlist import NamedItemList
|
15
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
16
|
+
from .odxtypes import ParameterValue, ParameterValueDict
|
17
|
+
from .parameters.createanyparameter import create_any_parameter_from_et
|
18
|
+
from .parameters.parameter import Parameter
|
19
|
+
from .snrefcontext import SnRefContext
|
20
|
+
from .specialdatagroup import SpecialDataGroup
|
8
21
|
from .utils import dataclass_fields_asdict
|
9
22
|
|
10
23
|
|
11
|
-
# TODO: The spec does not say that requests are basic structures. For
|
12
|
-
# now, we derive from it anyway because it simplifies the en- and
|
13
|
-
# decoding machinery...
|
14
24
|
@dataclass
|
15
|
-
class Request(
|
25
|
+
class Request(IdentifiableElement):
|
26
|
+
"""Represents all information related to an UDS request
|
27
|
+
|
28
|
+
This class implements the `CompositeCodec` interface.
|
29
|
+
"""
|
30
|
+
admin_data: Optional[AdminData]
|
31
|
+
parameters: NamedItemList[Parameter]
|
32
|
+
sdgs: List[SpecialDataGroup]
|
33
|
+
|
34
|
+
@property
|
35
|
+
def required_parameters(self) -> List[Parameter]:
|
36
|
+
return composite_codec_get_required_parameters(self)
|
37
|
+
|
38
|
+
@property
|
39
|
+
def free_parameters(self) -> List[Parameter]:
|
40
|
+
return composite_codec_get_free_parameters(self)
|
16
41
|
|
17
42
|
@staticmethod
|
18
43
|
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Request":
|
19
|
-
|
20
|
-
|
44
|
+
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
45
|
+
|
46
|
+
admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
|
47
|
+
parameters = NamedItemList([
|
48
|
+
create_any_parameter_from_et(et_parameter, doc_frags)
|
49
|
+
for et_parameter in et_element.iterfind("PARAMS/PARAM")
|
50
|
+
])
|
51
|
+
sdgs = [
|
52
|
+
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
53
|
+
]
|
54
|
+
|
55
|
+
return Request(admin_data=admin_data, parameters=parameters, sdgs=sdgs, **kwargs)
|
56
|
+
|
57
|
+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
58
|
+
result = {self.odx_id: self}
|
59
|
+
|
60
|
+
if self.admin_data is not None:
|
61
|
+
result.update(self.admin_data._build_odxlinks())
|
62
|
+
|
63
|
+
for param in self.parameters:
|
64
|
+
result.update(param._build_odxlinks())
|
65
|
+
|
66
|
+
for sdg in self.sdgs:
|
67
|
+
result.update(sdg._build_odxlinks())
|
68
|
+
|
69
|
+
return result
|
70
|
+
|
71
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
72
|
+
if self.admin_data is not None:
|
73
|
+
self.admin_data._resolve_odxlinks(odxlinks)
|
74
|
+
|
75
|
+
for param in self.parameters:
|
76
|
+
param._resolve_odxlinks(odxlinks)
|
77
|
+
|
78
|
+
for sdg in self.sdgs:
|
79
|
+
sdg._resolve_odxlinks(odxlinks)
|
80
|
+
|
81
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
82
|
+
context.request = self
|
83
|
+
context.parameters = self.parameters
|
84
|
+
|
85
|
+
if self.admin_data is not None:
|
86
|
+
self.admin_data._resolve_snrefs(context)
|
87
|
+
|
88
|
+
for param in self.parameters:
|
89
|
+
param._resolve_snrefs(context)
|
90
|
+
|
91
|
+
for sdg in self.sdgs:
|
92
|
+
sdg._resolve_snrefs(context)
|
93
|
+
|
94
|
+
context.request = None
|
95
|
+
context.parameters = None
|
96
|
+
|
97
|
+
def get_static_bit_length(self) -> Optional[int]:
|
98
|
+
return composite_codec_get_static_bit_length(self)
|
99
|
+
|
100
|
+
def print_free_parameters_info(self) -> None:
|
101
|
+
"""Print a human readable description of the composite codec's
|
102
|
+
free parameters to `stdout`
|
103
|
+
"""
|
104
|
+
from .parameterinfo import parameter_info
|
105
|
+
|
106
|
+
print(parameter_info(self.free_parameters), end="")
|
107
|
+
|
108
|
+
def encode(self, **kwargs: ParameterValue) -> bytearray:
|
109
|
+
encode_state = EncodeState(is_end_of_pdu=True)
|
110
|
+
|
111
|
+
self.encode_into_pdu(physical_value=kwargs, encode_state=encode_state)
|
112
|
+
|
113
|
+
return encode_state.coded_message
|
114
|
+
|
115
|
+
def decode(self, message: bytes) -> ParameterValueDict:
|
116
|
+
decode_state = DecodeState(coded_message=message)
|
117
|
+
param_values = self.decode_from_pdu(decode_state)
|
118
|
+
|
119
|
+
if not isinstance(param_values, dict):
|
120
|
+
odxraise("Decoding a request must result in a dictionary")
|
121
|
+
|
122
|
+
return cast(ParameterValueDict, param_values)
|
123
|
+
|
124
|
+
def encode_into_pdu(self, physical_value: Optional[ParameterValue],
|
125
|
+
encode_state: EncodeState) -> None:
|
126
|
+
composite_codec_encode_into_pdu(self, physical_value, encode_state)
|
127
|
+
|
128
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
129
|
+
return composite_codec_decode_from_pdu(self, decode_state)
|
21
130
|
|
22
|
-
|
131
|
+
def coded_const_prefix(self, request_prefix: bytes = b'') -> bytes:
|
132
|
+
return composite_codec_get_coded_const_prefix(self, request_prefix)
|
odxtools/response.py
CHANGED
@@ -1,14 +1,24 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from enum import Enum
|
4
|
-
from typing import List, Optional, cast
|
4
|
+
from typing import Any, Dict, List, Optional, cast
|
5
5
|
from xml.etree import ElementTree
|
6
6
|
|
7
|
-
from .
|
7
|
+
from .admindata import AdminData
|
8
|
+
from .codec import (composite_codec_decode_from_pdu, composite_codec_encode_into_pdu,
|
9
|
+
composite_codec_get_coded_const_prefix, composite_codec_get_free_parameters,
|
10
|
+
composite_codec_get_required_parameters, composite_codec_get_static_bit_length)
|
11
|
+
from .decodestate import DecodeState
|
12
|
+
from .element import IdentifiableElement
|
13
|
+
from .encodestate import EncodeState
|
8
14
|
from .exceptions import odxraise
|
9
|
-
from .
|
10
|
-
from .
|
11
|
-
from .
|
15
|
+
from .nameditemlist import NamedItemList
|
16
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
17
|
+
from .odxtypes import ParameterValue, ParameterValueDict
|
18
|
+
from .parameters.createanyparameter import create_any_parameter_from_et
|
19
|
+
from .parameters.parameter import Parameter
|
20
|
+
from .snrefcontext import SnRefContext
|
21
|
+
from .specialdatagroup import SpecialDataGroup
|
12
22
|
from .utils import dataclass_fields_asdict
|
13
23
|
|
14
24
|
|
@@ -18,17 +28,23 @@ class ResponseType(Enum):
|
|
18
28
|
GLOBAL_NEGATIVE = "GLOBAL-NEG-RESPONSE"
|
19
29
|
|
20
30
|
|
21
|
-
# TODO: The spec does not say that responses are basic structures. For
|
22
|
-
# now, we derive from it anyway because it simplifies the en- and
|
23
|
-
# decoding machinery...
|
24
31
|
@dataclass
|
25
|
-
class Response(
|
32
|
+
class Response(IdentifiableElement):
|
33
|
+
"""Represents all information related to an UDS response
|
34
|
+
|
35
|
+
This class implements the `CompositeCodec` interface.
|
36
|
+
"""
|
37
|
+
|
26
38
|
response_type: ResponseType
|
27
39
|
|
40
|
+
admin_data: Optional[AdminData]
|
41
|
+
parameters: NamedItemList[Parameter]
|
42
|
+
sdgs: List[SpecialDataGroup]
|
43
|
+
|
28
44
|
@staticmethod
|
29
45
|
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Response":
|
30
46
|
"""Reads a response."""
|
31
|
-
kwargs = dataclass_fields_asdict(
|
47
|
+
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
32
48
|
|
33
49
|
try:
|
34
50
|
response_type = ResponseType(et_element.tag)
|
@@ -36,19 +52,103 @@ class Response(BasicStructure):
|
|
36
52
|
response_type = cast(ResponseType, None)
|
37
53
|
odxraise(f"Encountered unknown response type '{et_element.tag}'")
|
38
54
|
|
39
|
-
|
55
|
+
admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
|
56
|
+
parameters = NamedItemList([
|
57
|
+
create_any_parameter_from_et(et_parameter, doc_frags)
|
58
|
+
for et_parameter in et_element.iterfind("PARAMS/PARAM")
|
59
|
+
])
|
60
|
+
sdgs = [
|
61
|
+
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
62
|
+
]
|
63
|
+
|
64
|
+
return Response(
|
65
|
+
response_type=response_type,
|
66
|
+
admin_data=admin_data,
|
67
|
+
parameters=parameters,
|
68
|
+
sdgs=sdgs,
|
69
|
+
**kwargs)
|
70
|
+
|
71
|
+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
72
|
+
result = {self.odx_id: self}
|
73
|
+
|
74
|
+
if self.admin_data is not None:
|
75
|
+
result.update(self.admin_data._build_odxlinks())
|
76
|
+
|
77
|
+
for param in self.parameters:
|
78
|
+
result.update(param._build_odxlinks())
|
79
|
+
|
80
|
+
for sdg in self.sdgs:
|
81
|
+
result.update(sdg._build_odxlinks())
|
82
|
+
|
83
|
+
return result
|
84
|
+
|
85
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
86
|
+
if self.admin_data is not None:
|
87
|
+
self.admin_data._resolve_odxlinks(odxlinks)
|
88
|
+
|
89
|
+
for param in self.parameters:
|
90
|
+
param._resolve_odxlinks(odxlinks)
|
91
|
+
|
92
|
+
for sdg in self.sdgs:
|
93
|
+
sdg._resolve_odxlinks(odxlinks)
|
94
|
+
|
95
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
96
|
+
context.response = self
|
97
|
+
context.parameters = self.parameters
|
98
|
+
|
99
|
+
if self.admin_data is not None:
|
100
|
+
self.admin_data._resolve_snrefs(context)
|
101
|
+
|
102
|
+
for param in self.parameters:
|
103
|
+
param._resolve_snrefs(context)
|
104
|
+
|
105
|
+
for sdg in self.sdgs:
|
106
|
+
sdg._resolve_snrefs(context)
|
107
|
+
|
108
|
+
context.response = None
|
109
|
+
context.parameters = None
|
110
|
+
|
111
|
+
def encode(self, coded_request: Optional[bytes] = None, **kwargs: ParameterValue) -> bytearray:
|
112
|
+
encode_state = EncodeState(triggering_request=coded_request, is_end_of_pdu=True)
|
113
|
+
|
114
|
+
self.encode_into_pdu(physical_value=kwargs, encode_state=encode_state)
|
115
|
+
|
116
|
+
return encode_state.coded_message
|
117
|
+
|
118
|
+
def decode(self, message: bytes) -> ParameterValueDict:
|
119
|
+
decode_state = DecodeState(coded_message=message)
|
120
|
+
param_values = self.decode_from_pdu(decode_state)
|
121
|
+
|
122
|
+
if not isinstance(param_values, dict):
|
123
|
+
odxraise("Decoding a response must result in a dictionary")
|
124
|
+
|
125
|
+
return cast(ParameterValueDict, param_values)
|
126
|
+
|
127
|
+
def encode_into_pdu(self, physical_value: Optional[ParameterValue],
|
128
|
+
encode_state: EncodeState) -> None:
|
129
|
+
composite_codec_encode_into_pdu(self, physical_value, encode_state)
|
130
|
+
|
131
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
132
|
+
return composite_codec_decode_from_pdu(self, decode_state)
|
133
|
+
|
134
|
+
def get_static_bit_length(self) -> Optional[int]:
|
135
|
+
return composite_codec_get_static_bit_length(self)
|
136
|
+
|
137
|
+
@property
|
138
|
+
def required_parameters(self) -> List[Parameter]:
|
139
|
+
return composite_codec_get_required_parameters(self)
|
140
|
+
|
141
|
+
@property
|
142
|
+
def free_parameters(self) -> List[Parameter]:
|
143
|
+
return composite_codec_get_free_parameters(self)
|
40
144
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
for param in self.parameters:
|
47
|
-
if isinstance(param, MatchingRequestParameter):
|
48
|
-
byte_pos = param.request_byte_position
|
49
|
-
byte_length = param.byte_length
|
145
|
+
def print_free_parameters_info(self) -> None:
|
146
|
+
"""Return a human readable description of the structure's
|
147
|
+
free parameters.
|
148
|
+
"""
|
149
|
+
from .parameterinfo import parameter_info
|
50
150
|
|
51
|
-
|
52
|
-
params[param.short_name] = val
|
151
|
+
print(parameter_info(self.free_parameters), end="")
|
53
152
|
|
54
|
-
|
153
|
+
def coded_const_prefix(self, request_prefix: bytes = b'') -> bytes:
|
154
|
+
return composite_codec_get_coded_const_prefix(self, request_prefix)
|
odxtools/scaleconstr.py
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from enum import Enum
|
4
|
-
from typing import Optional
|
4
|
+
from typing import List, Optional
|
5
5
|
from xml.etree import ElementTree
|
6
6
|
|
7
7
|
from .compumethods.limit import Limit
|
8
|
+
from .description import Description
|
8
9
|
from .exceptions import odxraise, odxrequire
|
10
|
+
from .odxlink import OdxDocFragment
|
9
11
|
from .odxtypes import DataType
|
10
|
-
from .utils import create_description_from_et
|
11
12
|
|
12
13
|
|
13
14
|
class ValidType(Enum):
|
@@ -23,18 +24,22 @@ class ScaleConstr:
|
|
23
24
|
"""
|
24
25
|
|
25
26
|
short_label: Optional[str]
|
26
|
-
description: Optional[
|
27
|
+
description: Optional[Description]
|
27
28
|
lower_limit: Optional[Limit]
|
28
29
|
upper_limit: Optional[Limit]
|
29
30
|
validity: ValidType
|
31
|
+
value_type: DataType
|
30
32
|
|
31
33
|
@staticmethod
|
32
|
-
def
|
34
|
+
def scale_constr_from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment], *,
|
35
|
+
value_type: DataType) -> "ScaleConstr":
|
33
36
|
short_label = et_element.findtext("SHORT-LABEL")
|
34
|
-
description =
|
37
|
+
description = Description.from_et(et_element.find("DESC"), doc_frags)
|
35
38
|
|
36
|
-
lower_limit = Limit.
|
37
|
-
|
39
|
+
lower_limit = Limit.limit_from_et(
|
40
|
+
et_element.find("LOWER-LIMIT"), doc_frags, value_type=value_type)
|
41
|
+
upper_limit = Limit.limit_from_et(
|
42
|
+
et_element.find("UPPER-LIMIT"), doc_frags, value_type=value_type)
|
38
43
|
|
39
44
|
validity_str = odxrequire(et_element.get("VALIDITY"))
|
40
45
|
try:
|
@@ -47,4 +52,5 @@ class ScaleConstr:
|
|
47
52
|
description=description,
|
48
53
|
lower_limit=lower_limit,
|
49
54
|
upper_limit=upper_limit,
|
50
|
-
validity=validity
|
55
|
+
validity=validity,
|
56
|
+
value_type=value_type)
|
odxtools/servicebinner.py
CHANGED
@@ -91,7 +91,7 @@ class ServiceBinner:
|
|
91
91
|
"""
|
92
92
|
result = StringIO()
|
93
93
|
result.write("[ ")
|
94
|
-
result.write(", ".join([f"0x{x}" for x in self._service_groups if x is not None]))
|
94
|
+
result.write(", ".join([f"0x{x:x}" for x in self._service_groups if x is not None]))
|
95
95
|
result.write(" ]")
|
96
96
|
|
97
97
|
return result.getvalue()
|
odxtools/singleecujob.py
CHANGED
@@ -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
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .diagcomm import DiagComm
|
@@ -10,11 +10,9 @@ from .negoutputparam import NegOutputParam
|
|
10
10
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
11
11
|
from .outputparam import OutputParam
|
12
12
|
from .progcode import ProgCode
|
13
|
+
from .snrefcontext import SnRefContext
|
13
14
|
from .utils import dataclass_fields_asdict
|
14
15
|
|
15
|
-
if TYPE_CHECKING:
|
16
|
-
from .diaglayer import DiagLayer
|
17
|
-
|
18
16
|
|
19
17
|
@dataclass
|
20
18
|
class SingleEcuJob(DiagComm):
|
@@ -88,14 +86,18 @@ class SingleEcuJob(DiagComm):
|
|
88
86
|
for neg_output_param in self.neg_output_params:
|
89
87
|
neg_output_param._resolve_odxlinks(odxlinks)
|
90
88
|
|
91
|
-
def _resolve_snrefs(self,
|
92
|
-
|
89
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
90
|
+
context.single_ecu_job = self
|
91
|
+
|
92
|
+
super()._resolve_snrefs(context)
|
93
93
|
|
94
94
|
for prog_code in self.prog_codes:
|
95
|
-
prog_code._resolve_snrefs(
|
95
|
+
prog_code._resolve_snrefs(context)
|
96
96
|
for input_param in self.input_params:
|
97
|
-
input_param._resolve_snrefs(
|
97
|
+
input_param._resolve_snrefs(context)
|
98
98
|
for output_param in self.output_params:
|
99
|
-
output_param._resolve_snrefs(
|
99
|
+
output_param._resolve_snrefs(context)
|
100
100
|
for neg_output_param in self.neg_output_params:
|
101
|
-
neg_output_param._resolve_snrefs(
|
101
|
+
neg_output_param._resolve_snrefs(context)
|
102
|
+
|
103
|
+
context.single_ecu_job = None
|
odxtools/snrefcontext.py
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import TYPE_CHECKING, List, Optional
|
4
|
+
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
from .database import Database
|
7
|
+
from .diaglayers.diaglayer import DiagLayer
|
8
|
+
from .diagservice import DiagService
|
9
|
+
from .parameters.parameter import Parameter
|
10
|
+
from .request import Request
|
11
|
+
from .response import Response
|
12
|
+
from .singleecujob import SingleEcuJob
|
13
|
+
from .statechart import StateChart
|
14
|
+
|
15
|
+
|
16
|
+
@dataclass
|
17
|
+
class SnRefContext:
|
18
|
+
"""Represents the context for which a short name reference ought
|
19
|
+
to be resolved
|
20
|
+
"""
|
21
|
+
|
22
|
+
database: Optional["Database"] = None
|
23
|
+
diag_layer: Optional["DiagLayer"] = None
|
24
|
+
diag_service: Optional["DiagService"] = None
|
25
|
+
single_ecu_job: Optional["SingleEcuJob"] = None
|
26
|
+
request: Optional["Request"] = None
|
27
|
+
response: Optional["Response"] = None
|
28
|
+
parameters: Optional[List["Parameter"]] = None
|
29
|
+
state_chart: Optional["StateChart"] = None
|
odxtools/specialdata.py
CHANGED
@@ -1,12 +1,10 @@
|
|
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 .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
7
|
-
|
8
|
-
if TYPE_CHECKING:
|
9
|
-
from .diaglayer import DiagLayer
|
7
|
+
from .snrefcontext import SnRefContext
|
10
8
|
|
11
9
|
|
12
10
|
@dataclass
|
@@ -21,7 +19,7 @@ class SpecialData:
|
|
21
19
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
22
20
|
pass
|
23
21
|
|
24
|
-
def _resolve_snrefs(self,
|
22
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
25
23
|
pass
|
26
24
|
|
27
25
|
@staticmethod
|
odxtools/specialdatagroup.py
CHANGED
@@ -1,22 +1,20 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional, Union
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
7
|
+
from .snrefcontext import SnRefContext
|
7
8
|
from .specialdata import SpecialData
|
8
9
|
from .specialdatagroupcaption import SpecialDataGroupCaption
|
9
10
|
|
10
|
-
if TYPE_CHECKING:
|
11
|
-
from .diaglayer import DiagLayer
|
12
|
-
|
13
11
|
|
14
12
|
@dataclass
|
15
13
|
class SpecialDataGroup:
|
16
14
|
sdg_caption: Optional[SpecialDataGroupCaption]
|
17
15
|
sdg_caption_ref: Optional[OdxLinkRef]
|
18
|
-
semantic_info: Optional[str] # the "SI" attribute
|
19
16
|
values: List[Union["SpecialDataGroup", SpecialData]]
|
17
|
+
semantic_info: Optional[str] # the "SI" attribute
|
20
18
|
|
21
19
|
@staticmethod
|
22
20
|
def from_et(et_element: ElementTree.Element,
|
@@ -53,7 +51,7 @@ class SpecialDataGroup:
|
|
53
51
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
54
52
|
result = {}
|
55
53
|
|
56
|
-
if self.sdg_caption is not None:
|
54
|
+
if self.sdg_caption_ref is None and self.sdg_caption is not None:
|
57
55
|
result.update(self.sdg_caption._build_odxlinks())
|
58
56
|
|
59
57
|
for val in self.values:
|
@@ -72,11 +70,11 @@ class SpecialDataGroup:
|
|
72
70
|
for val in self.values:
|
73
71
|
val._resolve_odxlinks(odxlinks)
|
74
72
|
|
75
|
-
def _resolve_snrefs(self,
|
73
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
76
74
|
# resolve the SNREFs of the caption, but only if the caption
|
77
75
|
# was specified by value, not by reference
|
78
76
|
if self.sdg_caption is not None and self.sdg_caption_ref is None:
|
79
|
-
self.sdg_caption._resolve_snrefs(
|
77
|
+
self.sdg_caption._resolve_snrefs(context)
|
80
78
|
|
81
79
|
for val in self.values:
|
82
|
-
val._resolve_snrefs(
|
80
|
+
val._resolve_snrefs(context)
|
@@ -1,16 +1,13 @@
|
|
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
|
5
4
|
from xml.etree import ElementTree
|
6
5
|
|
7
6
|
from .element import IdentifiableElement
|
8
7
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
8
|
+
from .snrefcontext import SnRefContext
|
9
9
|
from .utils import dataclass_fields_asdict
|
10
10
|
|
11
|
-
if TYPE_CHECKING:
|
12
|
-
from .diaglayer import DiagLayer
|
13
|
-
|
14
11
|
|
15
12
|
@dataclass
|
16
13
|
class SpecialDataGroupCaption(IdentifiableElement):
|
@@ -32,5 +29,5 @@ class SpecialDataGroupCaption(IdentifiableElement):
|
|
32
29
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
33
30
|
pass
|
34
31
|
|
35
|
-
def _resolve_snrefs(self,
|
32
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
36
33
|
pass
|