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/cli/list.py
CHANGED
@@ -4,9 +4,14 @@ from typing import Callable, List, Optional
|
|
4
4
|
|
5
5
|
import rich
|
6
6
|
|
7
|
+
from ..comparaminstance import ComparamInstance
|
7
8
|
from ..database import Database
|
9
|
+
from ..dataobjectproperty import DataObjectProperty
|
8
10
|
from ..diagcomm import DiagComm
|
9
|
-
from ..
|
11
|
+
from ..diaglayers.basevariant import BaseVariant
|
12
|
+
from ..diaglayers.diaglayer import DiagLayer
|
13
|
+
from ..diaglayers.ecuvariant import EcuVariant
|
14
|
+
from ..diaglayers.hierarchyelement import HierarchyElement
|
10
15
|
from ..diagservice import DiagService
|
11
16
|
from ..singleecujob import SingleEcuJob
|
12
17
|
from . import _parser_utils
|
@@ -47,7 +52,7 @@ def print_summary(odxdb: Database,
|
|
47
52
|
if diag_layers:
|
48
53
|
rich.print("\n")
|
49
54
|
rich.print(f"Overview of diagnostic layers: ")
|
50
|
-
print_dl_metrics(diag_layers
|
55
|
+
print_dl_metrics(diag_layers)
|
51
56
|
|
52
57
|
for dl in diag_layers:
|
53
58
|
rich.print("\n")
|
@@ -56,15 +61,14 @@ def print_summary(odxdb: Database,
|
|
56
61
|
|
57
62
|
all_services: List[DiagComm] = sorted(dl.services, key=lambda x: x.short_name)
|
58
63
|
|
59
|
-
|
60
|
-
|
64
|
+
if isinstance(dl, (BaseVariant, EcuVariant)):
|
65
|
+
for proto in dl.protocols:
|
66
|
+
if (can_rx_id := dl.get_can_receive_id(proto.short_name)) is not None:
|
67
|
+
rich.print(
|
68
|
+
f" CAN receive ID for protocol '{proto.short_name}': 0x{can_rx_id:x}")
|
61
69
|
|
62
|
-
|
63
|
-
|
64
|
-
rich.print(f" CAN receive ID for protocol '{proto.short_name}': 0x{can_rx_id:x}")
|
65
|
-
|
66
|
-
if (can_tx_id := dl.get_can_send_id(proto.short_name)) is not None:
|
67
|
-
rich.print(f" CAN send ID for protocol '{proto.short_name}': 0x{can_tx_id:x}")
|
70
|
+
if (can_tx_id := dl.get_can_send_id(proto.short_name)) is not None:
|
71
|
+
rich.print(f" CAN send ID for protocol '{proto.short_name}': 0x{can_tx_id:x}")
|
68
72
|
|
69
73
|
if dl.description:
|
70
74
|
desc = format_desc(dl.description, indent=2)
|
@@ -89,13 +93,14 @@ def print_summary(odxdb: Database,
|
|
89
93
|
print_pre_condition_states=print_pre_condition_states,
|
90
94
|
print_state_transitions=print_state_transitions,
|
91
95
|
print_audiences=print_audiences,
|
92
|
-
allow_unknown_bit_lengths=allow_unknown_bit_lengths
|
93
|
-
print_fn=rich.print)
|
96
|
+
allow_unknown_bit_lengths=allow_unknown_bit_lengths)
|
94
97
|
elif isinstance(service, SingleEcuJob):
|
95
98
|
rich.print(f" Single ECU job: {service.odx_id}")
|
96
99
|
else:
|
97
100
|
rich.print(f" Unidentifiable service: {service}")
|
98
|
-
|
101
|
+
ddd_spec = dl.diag_data_dictionary_spec
|
102
|
+
data_object_properties: List[
|
103
|
+
DataObjectProperty] = [] if ddd_spec is None else ddd_spec.data_object_props
|
99
104
|
if print_dops and len(data_object_properties) > 0:
|
100
105
|
rich.print("\n")
|
101
106
|
rich.print(f"The DOPs of the {dl.variant_type.value} '{dl.short_name}' are: ")
|
@@ -103,12 +108,16 @@ def print_summary(odxdb: Database,
|
|
103
108
|
data_object_properties, key=lambda x: (type(x).__name__, x.short_name)):
|
104
109
|
rich.print(" " + str(dop.short_name).replace("\n", "\n "))
|
105
110
|
|
106
|
-
|
111
|
+
comparam_refs: List[ComparamInstance] = []
|
112
|
+
if isinstance(dl, HierarchyElement):
|
113
|
+
comparam_refs = dl.comparam_refs
|
114
|
+
|
115
|
+
if print_comparams and len(comparam_refs) > 0:
|
107
116
|
rich.print("\n")
|
108
117
|
rich.print(
|
109
118
|
f"The communication parameters of the {dl.variant_type.value} '{dl.short_name}' are: "
|
110
119
|
)
|
111
|
-
for com_param in
|
120
|
+
for com_param in comparam_refs:
|
112
121
|
rich.print(f" {com_param.short_name}: {com_param.value}")
|
113
122
|
|
114
123
|
|
odxtools/cli/snoop.py
CHANGED
@@ -4,12 +4,13 @@
|
|
4
4
|
import argparse
|
5
5
|
import asyncio
|
6
6
|
import sys
|
7
|
-
from typing import Any, Type
|
7
|
+
from typing import Any, List, Optional, Type
|
8
8
|
|
9
9
|
import can
|
10
10
|
|
11
11
|
import odxtools.isotp_state_machine as ism
|
12
12
|
import odxtools.uds as uds
|
13
|
+
from odxtools.diaglayers.protocol import Protocol
|
13
14
|
from odxtools.exceptions import DecodeError
|
14
15
|
from odxtools.isotp_state_machine import IsoTpStateMachine
|
15
16
|
from odxtools.response import Response, ResponseType
|
@@ -245,21 +246,43 @@ def run(args: argparse.Namespace) -> None:
|
|
245
246
|
|
246
247
|
protocol_name = args.protocol
|
247
248
|
if odx_diag_layer is not None and protocol_name is not None:
|
248
|
-
|
249
|
+
protocols: Optional[List[Protocol]] = getattr(odx_diag_layer, "protocols", None)
|
250
|
+
|
251
|
+
if protocols is None:
|
252
|
+
print(f"ECU variant {odx_diag_layer.short_name} is of type "
|
253
|
+
f"{odx_diag_layer.variant_type.value} and thus does not "
|
254
|
+
f"feature any protocols")
|
255
|
+
sys.exit(1)
|
256
|
+
|
257
|
+
protocol_names = [x.short_name for x in protocols]
|
249
258
|
if protocol_name not in protocol_names:
|
250
259
|
print(f"ECU variant {odx_diag_layer.short_name} does not support "
|
251
260
|
f"a protocol named '{protocol_name}'. Supported protocols are:")
|
252
|
-
for x in
|
261
|
+
for x in protocols:
|
253
262
|
desc = "" if x.description is None else f": {x.description}"
|
254
263
|
print(f" {x.short_name}{desc}")
|
255
264
|
sys.exit(1)
|
256
265
|
|
257
266
|
# if no can IDs have been explicitly specified, take them from the DL
|
258
267
|
if args.rx is None and odx_diag_layer:
|
259
|
-
|
268
|
+
get_can_rx_id = getattr(odx_diag_layer, "get_can_receive_id", None)
|
269
|
+
if get_can_rx_id is None:
|
270
|
+
print(f"ECU variant {odx_diag_layer.short_name} is of type "
|
271
|
+
f"{odx_diag_layer.variant_type.value} and thus does not "
|
272
|
+
f"provide any communication parameters")
|
273
|
+
sys.exit(1)
|
274
|
+
|
275
|
+
args.rx = str(get_can_rx_id(protocol=protocol_name))
|
260
276
|
|
261
277
|
if args.tx is None and odx_diag_layer:
|
262
|
-
|
278
|
+
get_can_tx_id = getattr(odx_diag_layer, "get_can_send_id", None)
|
279
|
+
if get_can_tx_id is None:
|
280
|
+
print(f"ECU variant {odx_diag_layer.short_name} is of type "
|
281
|
+
f"{odx_diag_layer.variant_type.value} and thus does not "
|
282
|
+
f"provide any communication parameters")
|
283
|
+
sys.exit(1)
|
284
|
+
|
285
|
+
args.tx = str(get_can_tx_id(protocol=protocol_name))
|
263
286
|
|
264
287
|
if args.rx is None:
|
265
288
|
print(f"Could not determine a CAN receive ID.")
|
odxtools/codec.py
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
import typing
|
3
|
+
from typing import List, Optional, runtime_checkable
|
4
|
+
|
5
|
+
from .decodestate import DecodeState
|
6
|
+
from .encodestate import EncodeState
|
7
|
+
from .exceptions import EncodeError, odxraise
|
8
|
+
from .odxtypes import ParameterValue
|
9
|
+
from .parameters.codedconstparameter import CodedConstParameter
|
10
|
+
from .parameters.matchingrequestparameter import MatchingRequestParameter
|
11
|
+
from .parameters.parameter import Parameter
|
12
|
+
from .parameters.physicalconstantparameter import PhysicalConstantParameter
|
13
|
+
|
14
|
+
|
15
|
+
@runtime_checkable
|
16
|
+
class Codec(typing.Protocol):
|
17
|
+
"""Any object which can be en- or decoded to be transferred over
|
18
|
+
the wire implements this API.
|
19
|
+
"""
|
20
|
+
|
21
|
+
@property
|
22
|
+
def short_name(self) -> str:
|
23
|
+
return ""
|
24
|
+
|
25
|
+
def encode_into_pdu(self, physical_value: Optional[ParameterValue],
|
26
|
+
encode_state: EncodeState) -> None:
|
27
|
+
...
|
28
|
+
|
29
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
30
|
+
...
|
31
|
+
|
32
|
+
def get_static_bit_length(self) -> Optional[int]:
|
33
|
+
...
|
34
|
+
|
35
|
+
|
36
|
+
@runtime_checkable
|
37
|
+
class CompositeCodec(Codec, typing.Protocol):
|
38
|
+
"""Any object which can be en- or decoded to be transferred over
|
39
|
+
the wire which is composed of multiple parameter implements this
|
40
|
+
API.
|
41
|
+
|
42
|
+
"""
|
43
|
+
|
44
|
+
@property
|
45
|
+
def parameters(self) -> List[Parameter]:
|
46
|
+
return []
|
47
|
+
|
48
|
+
@property
|
49
|
+
def required_parameters(self) -> List[Parameter]:
|
50
|
+
return []
|
51
|
+
|
52
|
+
@property
|
53
|
+
def free_parameters(self) -> List[Parameter]:
|
54
|
+
return []
|
55
|
+
|
56
|
+
|
57
|
+
# some helper functions useful for composite codec objects
|
58
|
+
def composite_codec_get_static_bit_length(codec: CompositeCodec) -> Optional[int]:
|
59
|
+
"""Compute the length of a composite codec object in bits
|
60
|
+
|
61
|
+
This is basically the sum of the lengths of all parameters. If the
|
62
|
+
length of any parameter can only determined at runtime, `None` is
|
63
|
+
returned.
|
64
|
+
"""
|
65
|
+
|
66
|
+
cursor = 0
|
67
|
+
byte_length = 0
|
68
|
+
for param in codec.parameters:
|
69
|
+
param_bit_length = param.get_static_bit_length()
|
70
|
+
if param_bit_length is None:
|
71
|
+
# We were not able to calculate a static bit length
|
72
|
+
return None
|
73
|
+
elif param.byte_position is not None:
|
74
|
+
cursor = param.byte_position
|
75
|
+
|
76
|
+
cursor += ((param.bit_position or 0) + param_bit_length + 7) // 8
|
77
|
+
byte_length = max(byte_length, cursor)
|
78
|
+
|
79
|
+
return byte_length * 8
|
80
|
+
|
81
|
+
|
82
|
+
def composite_codec_get_required_parameters(codec: CompositeCodec) -> List[Parameter]:
|
83
|
+
"""Return the list of parameters which are required to be
|
84
|
+
specified for encoding the composite codec object
|
85
|
+
|
86
|
+
I.e., all free parameters that do not exhibit a default value.
|
87
|
+
"""
|
88
|
+
return [p for p in codec.parameters if p.is_required]
|
89
|
+
|
90
|
+
|
91
|
+
def composite_codec_get_free_parameters(codec: CompositeCodec) -> List[Parameter]:
|
92
|
+
"""Return the list of parameters which can be freely specified by
|
93
|
+
the user when encoding the composite codec object
|
94
|
+
|
95
|
+
This means all required parameters plus parameters that can be
|
96
|
+
omitted because they specify a default.
|
97
|
+
"""
|
98
|
+
return [p for p in codec.parameters if p.is_settable]
|
99
|
+
|
100
|
+
|
101
|
+
def composite_codec_get_coded_const_prefix(codec: CompositeCodec,
|
102
|
+
request_prefix: bytes = b'') -> bytes:
|
103
|
+
encode_state = EncodeState(coded_message=bytearray(), triggering_request=request_prefix)
|
104
|
+
|
105
|
+
for param in codec.parameters:
|
106
|
+
if (isinstance(param, MatchingRequestParameter) and param.request_byte_position < len(request_prefix)) or \
|
107
|
+
isinstance(param, (CodedConstParameter, PhysicalConstantParameter)):
|
108
|
+
param.encode_into_pdu(physical_value=None, encode_state=encode_state)
|
109
|
+
else:
|
110
|
+
break
|
111
|
+
|
112
|
+
return encode_state.coded_message
|
113
|
+
|
114
|
+
|
115
|
+
def composite_codec_encode_into_pdu(codec: CompositeCodec, physical_value: Optional[ParameterValue],
|
116
|
+
encode_state: EncodeState) -> None:
|
117
|
+
from .parameters.lengthkeyparameter import LengthKeyParameter
|
118
|
+
from .parameters.tablekeyparameter import TableKeyParameter
|
119
|
+
|
120
|
+
if not isinstance(physical_value, dict):
|
121
|
+
odxraise(
|
122
|
+
f"Expected a dictionary for the values of {codec.short_name}, "
|
123
|
+
f"got {type(physical_value).__name__}", EncodeError)
|
124
|
+
elif encode_state.cursor_bit_position != 0:
|
125
|
+
odxraise(
|
126
|
+
f"Compositional codec objecs must be byte aligned, but "
|
127
|
+
f"{codec.short_name} requested to be at bit position "
|
128
|
+
f"{encode_state.cursor_bit_position}", EncodeError)
|
129
|
+
encode_state.bit_position = 0
|
130
|
+
|
131
|
+
orig_origin = encode_state.origin_byte_position
|
132
|
+
encode_state.origin_byte_position = encode_state.cursor_byte_position
|
133
|
+
|
134
|
+
orig_is_end_of_pdu = encode_state.is_end_of_pdu
|
135
|
+
encode_state.is_end_of_pdu = False
|
136
|
+
|
137
|
+
# ensure that no values for unknown parameters are specified.
|
138
|
+
if not encode_state.allow_unknown_parameters:
|
139
|
+
param_names = {param.short_name for param in codec.parameters}
|
140
|
+
for param_value_name in physical_value:
|
141
|
+
if param_value_name not in param_names:
|
142
|
+
odxraise(f"Value for unknown parameter '{param_value_name}' specified "
|
143
|
+
f"for composite codec object {codec.short_name}")
|
144
|
+
|
145
|
+
for param in codec.parameters:
|
146
|
+
if id(param) == id(codec.parameters[-1]):
|
147
|
+
# The last parameter of the composite codec object is at
|
148
|
+
# the end of the PDU if the codec object itself is at the
|
149
|
+
# end of the PDU.
|
150
|
+
#
|
151
|
+
# TODO: This assumes that the last parameter specified in
|
152
|
+
# the ODX is located last in the PDU...
|
153
|
+
encode_state.is_end_of_pdu = orig_is_end_of_pdu
|
154
|
+
|
155
|
+
if isinstance(param, (LengthKeyParameter, TableKeyParameter)):
|
156
|
+
# At this point, we encode a placeholder value for length-
|
157
|
+
# and table keys, since these can be specified
|
158
|
+
# implicitly (i.e., by means of parameters that use
|
159
|
+
# these keys). To avoid getting an "overlapping
|
160
|
+
# parameter" warning, we must encode a value of zero
|
161
|
+
# into the PDU here and add the real value of the
|
162
|
+
# parameter in a post-processing step.
|
163
|
+
param.encode_placeholder_into_pdu(
|
164
|
+
physical_value=physical_value.get(param.short_name), encode_state=encode_state)
|
165
|
+
|
166
|
+
continue
|
167
|
+
|
168
|
+
if param.is_required and param.short_name not in physical_value:
|
169
|
+
odxraise(f"No value for required parameter {param.short_name} specified", EncodeError)
|
170
|
+
|
171
|
+
param_phys_value = physical_value.get(param.short_name)
|
172
|
+
param.encode_into_pdu(physical_value=param_phys_value, encode_state=encode_state)
|
173
|
+
|
174
|
+
encode_state.journal.append((param, param_phys_value))
|
175
|
+
|
176
|
+
encode_state.is_end_of_pdu = False
|
177
|
+
|
178
|
+
# encode the length- and table keys. This cannot be done above
|
179
|
+
# because we allow these to be defined implicitly (i.e. they
|
180
|
+
# are defined by their respective users)
|
181
|
+
for param in codec.parameters:
|
182
|
+
if not isinstance(param, (LengthKeyParameter, TableKeyParameter)):
|
183
|
+
# the current parameter is neither a length- nor a table key
|
184
|
+
continue
|
185
|
+
|
186
|
+
# Encode the value of the key parameter into the message
|
187
|
+
param.encode_value_into_pdu(encode_state=encode_state)
|
188
|
+
|
189
|
+
encode_state.origin_byte_position = orig_origin
|
190
|
+
|
191
|
+
|
192
|
+
def composite_codec_decode_from_pdu(codec: CompositeCodec,
|
193
|
+
decode_state: DecodeState) -> ParameterValue:
|
194
|
+
# move the origin since positions specified by sub-parameters of
|
195
|
+
# composite codec objects are relative to the beginning of the
|
196
|
+
# object.
|
197
|
+
orig_origin = decode_state.origin_byte_position
|
198
|
+
decode_state.origin_byte_position = decode_state.cursor_byte_position
|
199
|
+
|
200
|
+
result = {}
|
201
|
+
for param in codec.parameters:
|
202
|
+
value = param.decode_from_pdu(decode_state)
|
203
|
+
|
204
|
+
decode_state.journal.append((param, value))
|
205
|
+
result[param.short_name] = value
|
206
|
+
|
207
|
+
# decoding of the composite codec object finished. go back the
|
208
|
+
# original origin.
|
209
|
+
decode_state.origin_byte_position = orig_origin
|
210
|
+
|
211
|
+
return result
|
odxtools/commrelation.py
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
import warnings
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from enum import Enum
|
5
|
+
from typing import Any, Dict, List, Optional
|
6
|
+
from xml.etree import ElementTree
|
7
|
+
|
8
|
+
from .description import Description
|
9
|
+
from .diagcomm import DiagComm
|
10
|
+
from .diagservice import DiagService
|
11
|
+
from .exceptions import OdxWarning, odxraise, odxrequire
|
12
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
13
|
+
from .parameters.parameter import Parameter
|
14
|
+
from .snrefcontext import SnRefContext
|
15
|
+
|
16
|
+
|
17
|
+
class CommRelationValueType(Enum):
|
18
|
+
CURRENT = "CURRENT"
|
19
|
+
STORED = "STORED"
|
20
|
+
STATIC = "STATIC"
|
21
|
+
SUBSTITUTED = "SUBSTITUTED"
|
22
|
+
|
23
|
+
|
24
|
+
@dataclass
|
25
|
+
class CommRelation:
|
26
|
+
description: Optional[Description]
|
27
|
+
relation_type: str
|
28
|
+
diag_comm_ref: Optional[OdxLinkRef]
|
29
|
+
diag_comm_snref: Optional[str]
|
30
|
+
in_param_if_snref: Optional[str]
|
31
|
+
#in_param_if_snpathref: Optional[str] # TODO
|
32
|
+
out_param_if_snref: Optional[str]
|
33
|
+
#out_param_if_snpathref: Optional[str] # TODO
|
34
|
+
value_type_raw: Optional[CommRelationValueType]
|
35
|
+
|
36
|
+
@property
|
37
|
+
def diag_comm(self) -> DiagComm:
|
38
|
+
return self._diag_comm
|
39
|
+
|
40
|
+
@property
|
41
|
+
def in_param_if(self) -> Optional[Parameter]:
|
42
|
+
return self._in_param_if
|
43
|
+
|
44
|
+
@property
|
45
|
+
def out_param_if(self) -> Optional[Parameter]:
|
46
|
+
return self._out_param_if
|
47
|
+
|
48
|
+
@property
|
49
|
+
def value_type(self) -> CommRelationValueType:
|
50
|
+
if self.value_type_raw is None:
|
51
|
+
return CommRelationValueType.CURRENT
|
52
|
+
|
53
|
+
return self.value_type_raw
|
54
|
+
|
55
|
+
@staticmethod
|
56
|
+
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "CommRelation":
|
57
|
+
description = Description.from_et(et_element.find("DESC"), doc_frags)
|
58
|
+
relation_type = odxrequire(et_element.findtext("RELATION-TYPE"))
|
59
|
+
|
60
|
+
diag_comm_ref = OdxLinkRef.from_et(et_element.find("DIAG-COMM-REF"), doc_frags)
|
61
|
+
diag_comm_snref = None
|
62
|
+
if (diag_comm_snref_elem := et_element.find("DIAG-COMM-SNREF")) is not None:
|
63
|
+
diag_comm_snref = odxrequire(diag_comm_snref_elem.get("SHORT-NAME"))
|
64
|
+
|
65
|
+
in_param_if_snref = None
|
66
|
+
if (in_param_if_snref_elem := et_element.find("IN-PARAM-IF-SNREF")) is not None:
|
67
|
+
in_param_if_snref = odxrequire(in_param_if_snref_elem.get("SHORT-NAME"))
|
68
|
+
|
69
|
+
if et_element.find("IN-PARAM-IF-SNPATHREF") is not None:
|
70
|
+
warnings.warn("SNPATHREFs are not supported by odxtools yet", OdxWarning, stacklevel=1)
|
71
|
+
|
72
|
+
out_param_if_snref = None
|
73
|
+
if (out_param_if_snref_elem := et_element.find("OUT-PARAM-IF-SNREF")) is not None:
|
74
|
+
out_param_if_snref = odxrequire(out_param_if_snref_elem.get("SHORT-NAME"))
|
75
|
+
|
76
|
+
if et_element.find("OUT-PARAM-IF-SNPATHREF") is not None:
|
77
|
+
warnings.warn("SNPATHREFs are not supported by odxtools yet", OdxWarning, stacklevel=1)
|
78
|
+
|
79
|
+
value_type_raw = None
|
80
|
+
if (value_type_str := et_element.get("VALUE-TYPE")) is not None:
|
81
|
+
try:
|
82
|
+
value_type_raw = CommRelationValueType(value_type_str)
|
83
|
+
except ValueError:
|
84
|
+
odxraise(f"Encountered unknown comm relation value type '{value_type_str}'")
|
85
|
+
|
86
|
+
return CommRelation(
|
87
|
+
description=description,
|
88
|
+
relation_type=relation_type,
|
89
|
+
diag_comm_ref=diag_comm_ref,
|
90
|
+
diag_comm_snref=diag_comm_snref,
|
91
|
+
in_param_if_snref=in_param_if_snref,
|
92
|
+
out_param_if_snref=out_param_if_snref,
|
93
|
+
value_type_raw=value_type_raw)
|
94
|
+
|
95
|
+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
96
|
+
return {}
|
97
|
+
|
98
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
99
|
+
if self.diag_comm_ref is not None:
|
100
|
+
self._diag_comm = odxlinks.resolve(self.diag_comm_ref, DiagComm)
|
101
|
+
|
102
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
103
|
+
diag_layer = odxrequire(context.diag_layer)
|
104
|
+
|
105
|
+
if self.diag_comm_snref is not None:
|
106
|
+
self._diag_comm = resolve_snref(self.diag_comm_snref, diag_layer.diag_comms, DiagComm)
|
107
|
+
|
108
|
+
service = self.diag_comm
|
109
|
+
if not isinstance(service, DiagService):
|
110
|
+
odxraise(f"DIAG-VARIABLE references non-service {type(service).__name__} "
|
111
|
+
f"diagnostic communication")
|
112
|
+
|
113
|
+
self._in_param_if = None
|
114
|
+
if self.in_param_if_snref is not None:
|
115
|
+
self._in_param_if = resolve_snref(self.in_param_if_snref,
|
116
|
+
odxrequire(service.request).parameters, Parameter)
|
117
|
+
|
118
|
+
self._out_param_if = None
|
119
|
+
if self.out_param_if_snref is not None:
|
120
|
+
self._out_param_if = resolve_snref(self.out_param_if_snref,
|
121
|
+
odxrequire(service.positive_responses[0]).parameters,
|
122
|
+
Parameter)
|
odxtools/companydata.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, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .companyspecificinfo import CompanySpecificInfo
|
@@ -8,12 +8,10 @@ from .element import IdentifiableElement
|
|
8
8
|
from .exceptions import odxrequire
|
9
9
|
from .nameditemlist import NamedItemList
|
10
10
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
11
|
+
from .snrefcontext import SnRefContext
|
11
12
|
from .teammember import TeamMember
|
12
13
|
from .utils import dataclass_fields_asdict
|
13
14
|
|
14
|
-
if TYPE_CHECKING:
|
15
|
-
from .diaglayer import DiagLayer
|
16
|
-
|
17
15
|
|
18
16
|
@dataclass
|
19
17
|
class CompanyData(IdentifiableElement):
|
@@ -64,9 +62,9 @@ class CompanyData(IdentifiableElement):
|
|
64
62
|
if self.company_specific_info:
|
65
63
|
self.company_specific_info._resolve_odxlinks(odxlinks)
|
66
64
|
|
67
|
-
def _resolve_snrefs(self,
|
65
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
68
66
|
for tm in self.team_members:
|
69
|
-
tm._resolve_snrefs(
|
67
|
+
tm._resolve_snrefs(context)
|
70
68
|
|
71
69
|
if self.company_specific_info:
|
72
|
-
self.company_specific_info._resolve_snrefs(
|
70
|
+
self.company_specific_info._resolve_snrefs(context)
|
odxtools/companydocinfo.py
CHANGED
@@ -1,18 +1,15 @@
|
|
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 .companydata import CompanyData
|
7
|
-
from .createsdgs import create_sdgs_from_et
|
8
7
|
from .exceptions import odxrequire
|
9
8
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
9
|
+
from .snrefcontext import SnRefContext
|
10
10
|
from .specialdatagroup import SpecialDataGroup
|
11
11
|
from .teammember import TeamMember
|
12
12
|
|
13
|
-
if TYPE_CHECKING:
|
14
|
-
from .diaglayer import DiagLayer
|
15
|
-
|
16
13
|
|
17
14
|
@dataclass
|
18
15
|
class CompanyDocInfo:
|
@@ -37,7 +34,9 @@ class CompanyDocInfo:
|
|
37
34
|
OdxLinkRef.from_et(et_element.find("COMPANY-DATA-REF"), doc_frags))
|
38
35
|
team_member_ref = OdxLinkRef.from_et(et_element.find("TEAM-MEMBER-REF"), doc_frags)
|
39
36
|
doc_label = et_element.findtext("DOC-LABEL")
|
40
|
-
sdgs =
|
37
|
+
sdgs = [
|
38
|
+
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
39
|
+
]
|
41
40
|
|
42
41
|
return CompanyDocInfo(
|
43
42
|
company_data_ref=company_data_ref,
|
@@ -64,6 +63,6 @@ class CompanyDocInfo:
|
|
64
63
|
for sdg in self.sdgs:
|
65
64
|
sdg._resolve_odxlinks(odxlinks)
|
66
65
|
|
67
|
-
def _resolve_snrefs(self,
|
66
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
68
67
|
for sdg in self.sdgs:
|
69
|
-
sdg._resolve_snrefs(
|
68
|
+
sdg._resolve_snrefs(context)
|
odxtools/companyrevisioninfo.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 .companydata import CompanyData
|
7
7
|
from .exceptions import odxrequire
|
8
8
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
9
|
-
|
10
|
-
if TYPE_CHECKING:
|
11
|
-
from .diaglayer import DiagLayer
|
9
|
+
from .snrefcontext import SnRefContext
|
12
10
|
|
13
11
|
|
14
12
|
@dataclass
|
@@ -39,5 +37,5 @@ class CompanyRevisionInfo:
|
|
39
37
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
40
38
|
self._company_data = odxlinks.resolve(self.company_data_ref, CompanyData)
|
41
39
|
|
42
|
-
def _resolve_snrefs(self,
|
40
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
43
41
|
pass
|
odxtools/companyspecificinfo.py
CHANGED
@@ -1,16 +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
|
-
from .createsdgs import create_sdgs_from_et
|
7
6
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
8
7
|
from .relateddoc import RelatedDoc
|
8
|
+
from .snrefcontext import SnRefContext
|
9
9
|
from .specialdatagroup import SpecialDataGroup
|
10
10
|
|
11
|
-
if TYPE_CHECKING:
|
12
|
-
from .diaglayer import DiagLayer
|
13
|
-
|
14
11
|
|
15
12
|
@dataclass
|
16
13
|
class CompanySpecificInfo:
|
@@ -25,7 +22,9 @@ class CompanySpecificInfo:
|
|
25
22
|
for rd in et_element.iterfind("RELATED-DOCS/RELATED-DOC")
|
26
23
|
]
|
27
24
|
|
28
|
-
sdgs =
|
25
|
+
sdgs = [
|
26
|
+
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
27
|
+
]
|
29
28
|
|
30
29
|
return CompanySpecificInfo(related_docs=related_docs, sdgs=sdgs)
|
31
30
|
|
@@ -44,9 +43,9 @@ class CompanySpecificInfo:
|
|
44
43
|
for sdg in self.sdgs:
|
45
44
|
sdg._resolve_odxlinks(odxlinks)
|
46
45
|
|
47
|
-
def _resolve_snrefs(self,
|
46
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
48
47
|
for rd in self.related_docs:
|
49
|
-
rd._resolve_snrefs(
|
48
|
+
rd._resolve_snrefs(context)
|
50
49
|
|
51
50
|
for sdg in self.sdgs:
|
52
|
-
sdg._resolve_snrefs(
|
51
|
+
sdg._resolve_snrefs(context)
|
odxtools/comparam.py
CHANGED
@@ -1,17 +1,15 @@
|
|
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 .basecomparam import BaseComparam
|
7
7
|
from .dataobjectproperty import DataObjectProperty
|
8
8
|
from .exceptions import odxrequire
|
9
9
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
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
|
@dataclass
|
17
15
|
class Comparam(BaseComparam):
|
@@ -41,5 +39,5 @@ class Comparam(BaseComparam):
|
|
41
39
|
|
42
40
|
self._dop = odxlinks.resolve(self.dop_ref, DataObjectProperty)
|
43
41
|
|
44
|
-
def _resolve_snrefs(self,
|
45
|
-
super()._resolve_snrefs(
|
42
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
43
|
+
super()._resolve_snrefs(context)
|