odxtools 9.6.1__py3-none-any.whl → 10.0.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/additionalaudience.py +3 -3
- odxtools/addressing.py +8 -0
- odxtools/admindata.py +8 -8
- odxtools/audience.py +10 -10
- odxtools/basecomparam.py +7 -20
- odxtools/basevariantpattern.py +4 -5
- odxtools/basicstructure.py +12 -11
- odxtools/cli/_print_utils.py +35 -23
- odxtools/cli/browse.py +9 -9
- odxtools/cli/compare.py +24 -24
- odxtools/cli/decode.py +3 -4
- odxtools/cli/find.py +4 -5
- odxtools/cli/list.py +7 -7
- odxtools/cli/main.py +2 -2
- odxtools/cli/snoop.py +3 -3
- odxtools/codec.py +3 -186
- odxtools/commrelation.py +12 -19
- odxtools/commrelationvaluetype.py +9 -0
- odxtools/companydata.py +5 -5
- odxtools/companydocinfo.py +8 -8
- odxtools/companyrevisioninfo.py +5 -5
- odxtools/companyspecificinfo.py +5 -5
- odxtools/comparam.py +3 -3
- odxtools/comparaminstance.py +10 -10
- odxtools/comparamspec.py +3 -3
- odxtools/comparamsubset.py +5 -5
- odxtools/complexcomparam.py +7 -7
- odxtools/compositecodec.py +191 -0
- odxtools/compumethods/compucategory.py +13 -0
- odxtools/compumethods/compucodecompumethod.py +6 -5
- odxtools/compumethods/compuconst.py +4 -5
- odxtools/compumethods/compudefaultvalue.py +1 -2
- odxtools/compumethods/compuinternaltophys.py +6 -6
- odxtools/compumethods/compumethod.py +6 -17
- odxtools/compumethods/compuphystointernal.py +6 -6
- odxtools/compumethods/compurationalcoeffs.py +4 -4
- odxtools/compumethods/compuscale.py +9 -10
- odxtools/compumethods/createanycompumethod.py +1 -2
- odxtools/compumethods/identicalcompumethod.py +1 -2
- odxtools/compumethods/intervaltype.py +8 -0
- odxtools/compumethods/limit.py +13 -19
- odxtools/compumethods/linearcompumethod.py +4 -3
- odxtools/compumethods/linearsegment.py +14 -15
- odxtools/compumethods/ratfunccompumethod.py +5 -4
- odxtools/compumethods/ratfuncsegment.py +7 -8
- odxtools/compumethods/scalelinearcompumethod.py +10 -9
- odxtools/compumethods/scaleratfunccompumethod.py +6 -5
- odxtools/compumethods/tabintpcompumethod.py +19 -20
- odxtools/compumethods/texttablecompumethod.py +5 -4
- odxtools/createanycomparam.py +2 -4
- odxtools/createanydiagcodedtype.py +1 -2
- odxtools/database.py +9 -8
- odxtools/dataobjectproperty.py +10 -10
- odxtools/decodestate.py +5 -5
- odxtools/description.py +6 -22
- odxtools/determinenumberofitems.py +4 -4
- odxtools/diagclasstype.py +11 -0
- odxtools/diagcodedtype.py +7 -7
- odxtools/diagcomm.py +19 -42
- odxtools/diagdatadictionaryspec.py +6 -6
- odxtools/diaglayercontainer.py +4 -4
- odxtools/diaglayers/basevariant.py +10 -9
- odxtools/diaglayers/basevariantraw.py +9 -9
- odxtools/diaglayers/diaglayer.py +20 -19
- odxtools/diaglayers/diaglayerraw.py +10 -10
- odxtools/diaglayers/diaglayertype.py +1 -2
- odxtools/diaglayers/ecushareddata.py +4 -4
- odxtools/diaglayers/ecushareddataraw.py +6 -6
- odxtools/diaglayers/ecuvariant.py +11 -10
- odxtools/diaglayers/ecuvariantraw.py +9 -9
- odxtools/diaglayers/functionalgroup.py +8 -7
- odxtools/diaglayers/functionalgroupraw.py +7 -7
- odxtools/diaglayers/hierarchyelement.py +43 -49
- odxtools/diaglayers/hierarchyelementraw.py +4 -4
- odxtools/diaglayers/protocol.py +4 -4
- odxtools/diaglayers/protocolraw.py +6 -6
- odxtools/diagnostictroublecode.py +8 -8
- odxtools/diagservice.py +21 -97
- odxtools/diagvariable.py +14 -14
- odxtools/docrevision.py +11 -11
- odxtools/dopbase.py +6 -6
- odxtools/dtcconnector.py +45 -0
- odxtools/dtcdop.py +15 -56
- odxtools/dynamicendmarkerfield.py +5 -4
- odxtools/dynamiclengthfield.py +5 -4
- odxtools/dyndefinedspec.py +7 -159
- odxtools/dynenddopref.py +5 -5
- odxtools/dyniddefmodeinfo.py +161 -0
- odxtools/ecuvariantpattern.py +4 -5
- odxtools/element.py +5 -6
- odxtools/encodestate.py +11 -11
- odxtools/encoding.py +2 -3
- odxtools/endofpdufield.py +6 -6
- odxtools/envdataconnector.py +49 -0
- odxtools/environmentdata.py +3 -4
- odxtools/environmentdatadescription.py +11 -11
- odxtools/exceptions.py +5 -5
- odxtools/externalaccessmethod.py +22 -0
- odxtools/externaldoc.py +23 -0
- odxtools/field.py +9 -10
- odxtools/functionalclass.py +4 -4
- odxtools/inputparam.py +6 -6
- odxtools/internalconstr.py +4 -5
- odxtools/isotp_state_machine.py +12 -11
- odxtools/leadinglengthinfotype.py +2 -3
- odxtools/library.py +5 -5
- odxtools/linkeddtcdop.py +62 -0
- odxtools/loadfile.py +5 -6
- odxtools/matchingbasevariantparameter.py +2 -3
- odxtools/matchingparameter.py +7 -7
- odxtools/minmaxlengthtype.py +5 -11
- odxtools/modification.py +4 -4
- odxtools/multiplexer.py +11 -11
- odxtools/multiplexercase.py +6 -6
- odxtools/multiplexerdefaultcase.py +6 -6
- odxtools/multiplexerswitchkey.py +4 -4
- odxtools/nameditemlist.py +14 -14
- odxtools/negoutputparam.py +3 -3
- odxtools/obd.py +1 -2
- odxtools/odxcategory.py +6 -6
- odxtools/odxlink.py +19 -20
- odxtools/odxtypes.py +21 -18
- odxtools/outputparam.py +4 -4
- odxtools/parameterinfo.py +2 -2
- odxtools/parameters/codedconstparameter.py +5 -5
- odxtools/parameters/createanyparameter.py +1 -2
- odxtools/parameters/dynamicparameter.py +2 -3
- odxtools/parameters/lengthkeyparameter.py +5 -5
- odxtools/parameters/matchingrequestparameter.py +3 -4
- odxtools/parameters/nrcconstparameter.py +7 -7
- odxtools/parameters/parameter.py +11 -11
- odxtools/parameters/parameterwithdop.py +9 -9
- odxtools/parameters/physicalconstantparameter.py +4 -4
- odxtools/parameters/reservedparameter.py +3 -4
- odxtools/parameters/rowfragment.py +7 -0
- odxtools/parameters/systemparameter.py +2 -3
- odxtools/parameters/tableentryparameter.py +4 -9
- odxtools/parameters/tablekeyparameter.py +10 -10
- odxtools/parameters/tablestructparameter.py +7 -7
- odxtools/parameters/valueparameter.py +7 -7
- odxtools/paramlengthinfotype.py +5 -3
- odxtools/parentref.py +9 -9
- odxtools/physicaldimension.py +11 -11
- odxtools/physicaltype.py +4 -12
- odxtools/posresponsesuppressible.py +72 -0
- odxtools/preconditionstateref.py +7 -7
- odxtools/progcode.py +6 -6
- odxtools/protstack.py +4 -4
- odxtools/radix.py +9 -0
- odxtools/relateddiagcommref.py +22 -0
- odxtools/relateddoc.py +6 -6
- odxtools/request.py +14 -12
- odxtools/response.py +15 -13
- odxtools/scaleconstr.py +4 -12
- odxtools/servicebinner.py +5 -5
- odxtools/singleecujob.py +4 -4
- odxtools/snrefcontext.py +2 -2
- odxtools/specialdata.py +5 -5
- odxtools/specialdatagroup.py +9 -9
- odxtools/specialdatagroupcaption.py +3 -3
- odxtools/standardizationlevel.py +9 -0
- odxtools/standardlengthtype.py +12 -21
- odxtools/state.py +3 -3
- odxtools/statechart.py +4 -4
- odxtools/statemachine.py +4 -3
- odxtools/statetransition.py +5 -18
- odxtools/statetransitionref.py +18 -18
- odxtools/staticfield.py +5 -4
- odxtools/structure.py +2 -3
- odxtools/subcomponent.py +12 -245
- odxtools/subcomponentparamconnector.py +103 -0
- odxtools/subcomponentpattern.py +42 -0
- odxtools/swvariable.py +3 -4
- odxtools/table.py +17 -55
- odxtools/tablediagcommconnector.py +47 -0
- odxtools/tablerow.py +30 -30
- odxtools/tablerowconnector.py +46 -0
- odxtools/teammember.py +11 -11
- odxtools/templates/macros/printService.xml.jinja2 +2 -1
- odxtools/termination.py +8 -0
- odxtools/text.py +2 -3
- odxtools/transmode.py +9 -0
- odxtools/uds.py +2 -3
- odxtools/unit.py +9 -9
- odxtools/unitgroup.py +6 -11
- odxtools/unitgroupcategory.py +7 -0
- odxtools/unitspec.py +6 -6
- odxtools/usage.py +9 -0
- odxtools/utils.py +31 -2
- odxtools/validtype.py +9 -0
- odxtools/variablegroup.py +2 -2
- odxtools/variantmatcher.py +10 -10
- odxtools/variantpattern.py +3 -3
- odxtools/version.py +2 -2
- odxtools/writepdxfile.py +5 -5
- odxtools/xdoc.py +9 -9
- {odxtools-9.6.1.dist-info → odxtools-10.0.0.dist-info}/METADATA +4 -5
- odxtools-10.0.0.dist-info/RECORD +264 -0
- odxtools-9.6.1.dist-info/RECORD +0 -238
- {odxtools-9.6.1.dist-info → odxtools-10.0.0.dist-info}/WHEEL +0 -0
- {odxtools-9.6.1.dist-info → odxtools-10.0.0.dist-info}/entry_points.txt +0 -0
- {odxtools-9.6.1.dist-info → odxtools-10.0.0.dist-info}/licenses/LICENSE +0 -0
- {odxtools-9.6.1.dist-info → odxtools-10.0.0.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,11 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
import re
|
3
3
|
import warnings
|
4
|
+
from collections.abc import Callable, Iterable
|
4
5
|
from copy import deepcopy
|
5
6
|
from dataclasses import dataclass
|
6
7
|
from functools import cached_property
|
7
|
-
from typing import
|
8
|
-
Union, cast)
|
8
|
+
from typing import TYPE_CHECKING, Any, TypeVar, Union, cast
|
9
9
|
from xml.etree import ElementTree
|
10
10
|
|
11
11
|
from ..additionalaudience import AdditionalAudience
|
@@ -47,7 +47,7 @@ class HierarchyElement(DiagLayer):
|
|
47
47
|
|
48
48
|
@staticmethod
|
49
49
|
def from_et(et_element: ElementTree.Element,
|
50
|
-
doc_frags:
|
50
|
+
doc_frags: list[OdxDocFragment]) -> "HierarchyElement":
|
51
51
|
hierarchy_element_raw = HierarchyElementRaw.from_et(et_element, doc_frags)
|
52
52
|
|
53
53
|
return HierarchyElement(diag_layer_raw=hierarchy_element_raw)
|
@@ -62,7 +62,7 @@ class HierarchyElement(DiagLayer):
|
|
62
62
|
"The raw diagnostic layer passed to HierarchyElement "
|
63
63
|
"must be a HierarchyElementRaw")
|
64
64
|
|
65
|
-
def _build_odxlinks(self) ->
|
65
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
66
66
|
result = super()._build_odxlinks()
|
67
67
|
|
68
68
|
return result
|
@@ -73,7 +73,7 @@ class HierarchyElement(DiagLayer):
|
|
73
73
|
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
74
74
|
super()._resolve_snrefs(context)
|
75
75
|
|
76
|
-
def __deepcopy__(self, memo:
|
76
|
+
def __deepcopy__(self, memo: dict[int, Any]) -> Any:
|
77
77
|
"""Create a deep copy of the hierarchy element
|
78
78
|
|
79
79
|
Note that the copied diagnostic layer is not fully
|
@@ -121,13 +121,13 @@ class HierarchyElement(DiagLayer):
|
|
121
121
|
unit_groups = self._compute_available_unit_groups()
|
122
122
|
|
123
123
|
# convenience variable for the locally-defined unit spec
|
124
|
-
local_unit_spec:
|
124
|
+
local_unit_spec: UnitSpec | None
|
125
125
|
if self.diag_layer_raw.diag_data_dictionary_spec is not None:
|
126
126
|
local_unit_spec = self.diag_layer_raw.diag_data_dictionary_spec.unit_spec
|
127
127
|
else:
|
128
128
|
local_unit_spec = None
|
129
129
|
|
130
|
-
unit_spec:
|
130
|
+
unit_spec: UnitSpec | None
|
131
131
|
if local_unit_spec is None and not unit_groups:
|
132
132
|
# no locally defined unit spec and no inherited unit groups
|
133
133
|
unit_spec = None
|
@@ -188,8 +188,8 @@ class HierarchyElement(DiagLayer):
|
|
188
188
|
tables = self._compute_available_ddd_spec_items(
|
189
189
|
lambda ddd_spec: ddd_spec.tables, lambda parent_ref: parent_ref.not_inherited_tables)
|
190
190
|
|
191
|
-
ddds_admin_data:
|
192
|
-
ddds_sdgs:
|
191
|
+
ddds_admin_data: AdminData | None = None
|
192
|
+
ddds_sdgs: list[SpecialDataGroup] = []
|
193
193
|
if self.diag_layer_raw.diag_data_dictionary_spec:
|
194
194
|
ddds_admin_data = self.diag_layer_raw.diag_data_dictionary_spec.admin_data
|
195
195
|
ddds_sdgs = self.diag_layer_raw.diag_data_dictionary_spec.sdgs
|
@@ -291,7 +291,7 @@ class HierarchyElement(DiagLayer):
|
|
291
291
|
|
292
292
|
local_objects = get_local_objects(self)
|
293
293
|
local_object_short_names = {x.short_name for x in local_objects}
|
294
|
-
result_dict:
|
294
|
+
result_dict: dict[str, tuple[TNamed, DiagLayer]] = {}
|
295
295
|
|
296
296
|
# populate the result dictionary with the inherited objects
|
297
297
|
for parent_ref in self._get_parent_refs_sorted_by_priority(reverse=True):
|
@@ -361,7 +361,7 @@ class HierarchyElement(DiagLayer):
|
|
361
361
|
def get_local_objects_fn(dl: DiagLayer) -> Iterable[DiagComm]:
|
362
362
|
return dl._get_local_diag_comms(odxlinks)
|
363
363
|
|
364
|
-
def not_inherited_fn(parent_ref: ParentRef) ->
|
364
|
+
def not_inherited_fn(parent_ref: ParentRef) -> list[str]:
|
365
365
|
return parent_ref.not_inherited_diag_comms
|
366
366
|
|
367
367
|
return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
|
@@ -372,7 +372,7 @@ class HierarchyElement(DiagLayer):
|
|
372
372
|
def get_local_objects_fn(dl: DiagLayer) -> Iterable[Response]:
|
373
373
|
return dl.diag_layer_raw.global_negative_responses
|
374
374
|
|
375
|
-
def not_inherited_fn(parent_ref: ParentRef) ->
|
375
|
+
def not_inherited_fn(parent_ref: ParentRef) -> list[str]:
|
376
376
|
return parent_ref.not_inherited_global_neg_responses
|
377
377
|
|
378
378
|
return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
|
@@ -380,7 +380,7 @@ class HierarchyElement(DiagLayer):
|
|
380
380
|
def _compute_available_ddd_spec_items(
|
381
381
|
self,
|
382
382
|
include: Callable[[DiagDataDictionarySpec], Iterable[TNamed]],
|
383
|
-
exclude: Callable[["ParentRef"],
|
383
|
+
exclude: Callable[["ParentRef"], list[str]],
|
384
384
|
) -> NamedItemList[TNamed]:
|
385
385
|
|
386
386
|
def get_local_objects_fn(dl: DiagLayer) -> Iterable[TNamed]:
|
@@ -396,7 +396,7 @@ class HierarchyElement(DiagLayer):
|
|
396
396
|
def get_local_objects_fn(dl: DiagLayer) -> Iterable[FunctionalClass]:
|
397
397
|
return dl.diag_layer_raw.functional_classes
|
398
398
|
|
399
|
-
def not_inherited_fn(parent_ref: ParentRef) ->
|
399
|
+
def not_inherited_fn(parent_ref: ParentRef) -> list[str]:
|
400
400
|
return []
|
401
401
|
|
402
402
|
return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
|
@@ -406,7 +406,7 @@ class HierarchyElement(DiagLayer):
|
|
406
406
|
def get_local_objects_fn(dl: DiagLayer) -> Iterable[AdditionalAudience]:
|
407
407
|
return dl.diag_layer_raw.additional_audiences
|
408
408
|
|
409
|
-
def not_inherited_fn(parent_ref: ParentRef) ->
|
409
|
+
def not_inherited_fn(parent_ref: ParentRef) -> list[str]:
|
410
410
|
return []
|
411
411
|
|
412
412
|
return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
|
@@ -416,7 +416,7 @@ class HierarchyElement(DiagLayer):
|
|
416
416
|
def get_local_objects_fn(dl: DiagLayer) -> Iterable[StateChart]:
|
417
417
|
return dl.diag_layer_raw.state_charts
|
418
418
|
|
419
|
-
def not_inherited_fn(parent_ref: ParentRef) ->
|
419
|
+
def not_inherited_fn(parent_ref: ParentRef) -> list[str]:
|
420
420
|
return []
|
421
421
|
|
422
422
|
return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
|
@@ -426,7 +426,7 @@ class HierarchyElement(DiagLayer):
|
|
426
426
|
def get_local_objects_fn(dl: DiagLayer) -> Iterable[UnitGroup]:
|
427
427
|
return dl._get_local_unit_groups()
|
428
428
|
|
429
|
-
def not_inherited_fn(parent_ref: ParentRef) ->
|
429
|
+
def not_inherited_fn(parent_ref: ParentRef) -> list[str]:
|
430
430
|
return []
|
431
431
|
|
432
432
|
return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
|
@@ -502,7 +502,7 @@ class HierarchyElement(DiagLayer):
|
|
502
502
|
#####
|
503
503
|
# <communication parameter handling>
|
504
504
|
#####
|
505
|
-
def _compute_available_commmunication_parameters(self) ->
|
505
|
+
def _compute_available_commmunication_parameters(self) -> list[ComparamInstance]:
|
506
506
|
"""Compute the list of communication parameters that apply to
|
507
507
|
the diagnostic layer
|
508
508
|
|
@@ -526,7 +526,7 @@ class HierarchyElement(DiagLayer):
|
|
526
526
|
without a specified protocol are taken as fallbacks...
|
527
527
|
|
528
528
|
"""
|
529
|
-
com_params_dict:
|
529
|
+
com_params_dict: dict[tuple[str, str | None], ComparamInstance] = {}
|
530
530
|
|
531
531
|
# Look in parent refs for inherited communication
|
532
532
|
# parameters. First fetch the communication parameters from
|
@@ -564,7 +564,7 @@ class HierarchyElement(DiagLayer):
|
|
564
564
|
"""
|
565
565
|
from .protocol import Protocol
|
566
566
|
|
567
|
-
result_dict:
|
567
|
+
result_dict: dict[str, Protocol] = {}
|
568
568
|
|
569
569
|
for parent_ref in getattr(self, "parent_refs", []):
|
570
570
|
for prot in getattr(parent_ref.layer, "protocols", []):
|
@@ -579,15 +579,15 @@ class HierarchyElement(DiagLayer):
|
|
579
579
|
self,
|
580
580
|
cp_short_name: str,
|
581
581
|
*,
|
582
|
-
protocol:
|
583
|
-
) ->
|
582
|
+
protocol: Union[str, "Protocol"] | None = None,
|
583
|
+
) -> ComparamInstance | None:
|
584
584
|
"""Find a specific communication parameter according to some criteria.
|
585
585
|
|
586
586
|
Setting a given parameter to `None` means "don't care"."""
|
587
587
|
|
588
588
|
from .protocol import Protocol
|
589
589
|
|
590
|
-
protocol_name:
|
590
|
+
protocol_name: str | None
|
591
591
|
if isinstance(protocol, Protocol):
|
592
592
|
protocol_name = protocol.short_name
|
593
593
|
else:
|
@@ -611,8 +611,7 @@ class HierarchyElement(DiagLayer):
|
|
611
611
|
return cps[0]
|
612
612
|
|
613
613
|
def get_max_can_payload_size(self,
|
614
|
-
protocol:
|
615
|
-
"Protocol"]] = None) -> Optional[int]:
|
614
|
+
protocol: Union[str, "Protocol"] | None = None) -> int | None:
|
616
615
|
"""Return the maximum size of a CAN frame payload that can be
|
617
616
|
transmitted in bytes.
|
618
617
|
|
@@ -642,13 +641,13 @@ class HierarchyElement(DiagLayer):
|
|
642
641
|
# unexpected format of parameter value
|
643
642
|
return 8
|
644
643
|
|
645
|
-
def uses_can(self, protocol:
|
644
|
+
def uses_can(self, protocol: Union[str, "Protocol"] | None = None) -> bool:
|
646
645
|
"""
|
647
646
|
Check if CAN ought to be used as the link layer protocol.
|
648
647
|
"""
|
649
648
|
return self.get_can_receive_id(protocol=protocol) is not None
|
650
649
|
|
651
|
-
def uses_can_fd(self, protocol:
|
650
|
+
def uses_can_fd(self, protocol: Union[str, "Protocol"] | None = None) -> bool:
|
652
651
|
"""Check if CAN-FD ought to be used.
|
653
652
|
|
654
653
|
If the ECU is not using CAN-FD for the specified protocol, `False`
|
@@ -667,7 +666,7 @@ class HierarchyElement(DiagLayer):
|
|
667
666
|
|
668
667
|
return "CANFD" in com_param.value
|
669
668
|
|
670
|
-
def get_can_baudrate(self, protocol:
|
669
|
+
def get_can_baudrate(self, protocol: Union[str, "Protocol"] | None = None) -> int | None:
|
671
670
|
"""Baudrate of the CAN bus which is used by the ECU [bits/s]
|
672
671
|
|
673
672
|
If the ECU is not using CAN for the specified protocol, None
|
@@ -684,8 +683,7 @@ class HierarchyElement(DiagLayer):
|
|
684
683
|
|
685
684
|
return int(val)
|
686
685
|
|
687
|
-
def get_can_fd_baudrate(self,
|
688
|
-
protocol: Optional[Union[str, "Protocol"]] = None) -> Optional[int]:
|
686
|
+
def get_can_fd_baudrate(self, protocol: Union[str, "Protocol"] | None = None) -> int | None:
|
689
687
|
"""Data baudrate of the CAN bus which is used by the ECU [bits/s]
|
690
688
|
|
691
689
|
If the ECU is not using CAN-FD for the specified protocol,
|
@@ -704,8 +702,7 @@ class HierarchyElement(DiagLayer):
|
|
704
702
|
|
705
703
|
return int(val)
|
706
704
|
|
707
|
-
def get_can_receive_id(self,
|
708
|
-
protocol: Optional[Union[str, "Protocol"]] = None) -> Optional[int]:
|
705
|
+
def get_can_receive_id(self, protocol: Union[str, "Protocol"] | None = None) -> int | None:
|
709
706
|
"""CAN ID to which the ECU listens for diagnostic messages"""
|
710
707
|
com_param = self.get_comparam("CP_UniqueRespIdTable", protocol=protocol)
|
711
708
|
if com_param is None:
|
@@ -724,7 +721,7 @@ class HierarchyElement(DiagLayer):
|
|
724
721
|
|
725
722
|
return int(result)
|
726
723
|
|
727
|
-
def get_can_send_id(self, protocol:
|
724
|
+
def get_can_send_id(self, protocol: Union[str, "Protocol"] | None = None) -> int | None:
|
728
725
|
"""CAN ID to which the ECU sends replies to diagnostic messages"""
|
729
726
|
|
730
727
|
# this hopefully resolves to the 'CP_UniqueRespIdTable'
|
@@ -749,8 +746,7 @@ class HierarchyElement(DiagLayer):
|
|
749
746
|
|
750
747
|
return int(result)
|
751
748
|
|
752
|
-
def get_can_func_req_id(self,
|
753
|
-
protocol: Optional[Union[str, "Protocol"]] = None) -> Optional[int]:
|
749
|
+
def get_can_func_req_id(self, protocol: Union[str, "Protocol"] | None = None) -> int | None:
|
754
750
|
"""CAN Functional Request Id."""
|
755
751
|
com_param = self.get_comparam("CP_CanFuncReqId", protocol=protocol)
|
756
752
|
if com_param is None:
|
@@ -764,8 +760,7 @@ class HierarchyElement(DiagLayer):
|
|
764
760
|
return int(result)
|
765
761
|
|
766
762
|
def get_doip_logical_ecu_address(self,
|
767
|
-
protocol:
|
768
|
-
"Protocol"]] = None) -> Optional[int]:
|
763
|
+
protocol: Union[str, "Protocol"] | None = None) -> int | None:
|
769
764
|
"""Return the address of the ECU when using functional addressing.
|
770
765
|
|
771
766
|
The parameter protocol is used to distinguish between
|
@@ -796,8 +791,8 @@ class HierarchyElement(DiagLayer):
|
|
796
791
|
return int(ecu_addr)
|
797
792
|
|
798
793
|
def get_doip_logical_gateway_address(self,
|
799
|
-
protocol:
|
800
|
-
) ->
|
794
|
+
protocol: Union[str, "Protocol"] | None = None
|
795
|
+
) -> int | None:
|
801
796
|
"""The logical gateway address for the diagnosis over IP transport protocol"""
|
802
797
|
|
803
798
|
# retrieve CP_DoIPLogicalGatewayAddress from the
|
@@ -814,8 +809,8 @@ class HierarchyElement(DiagLayer):
|
|
814
809
|
return int(result)
|
815
810
|
|
816
811
|
def get_doip_logical_tester_address(self,
|
817
|
-
protocol:
|
818
|
-
) ->
|
812
|
+
protocol: Union[str, "Protocol"] | None = None
|
813
|
+
) -> int | None:
|
819
814
|
"""DoIp logical gateway address"""
|
820
815
|
|
821
816
|
# retrieve CP_DoIPLogicalTesterAddress from the
|
@@ -832,8 +827,8 @@ class HierarchyElement(DiagLayer):
|
|
832
827
|
return int(result)
|
833
828
|
|
834
829
|
def get_doip_logical_functional_address(self,
|
835
|
-
protocol:
|
836
|
-
) ->
|
830
|
+
protocol: Union[str, "Protocol"] | None = None
|
831
|
+
) -> int | None:
|
837
832
|
"""The logical functional DoIP address of the ECU."""
|
838
833
|
|
839
834
|
# retrieve CP_DoIPLogicalFunctionalAddress from the
|
@@ -853,8 +848,8 @@ class HierarchyElement(DiagLayer):
|
|
853
848
|
return int(result)
|
854
849
|
|
855
850
|
def get_doip_routing_activation_timeout(self,
|
856
|
-
protocol:
|
857
|
-
) ->
|
851
|
+
protocol: Union[str, "Protocol"] | None = None
|
852
|
+
) -> float | None:
|
858
853
|
"""The timout for the DoIP routing activation request in seconds"""
|
859
854
|
|
860
855
|
# retrieve CP_DoIPRoutingActivationTimeout from the
|
@@ -871,8 +866,8 @@ class HierarchyElement(DiagLayer):
|
|
871
866
|
return float(result) / 1e6
|
872
867
|
|
873
868
|
def get_doip_routing_activation_type(self,
|
874
|
-
protocol:
|
875
|
-
) ->
|
869
|
+
protocol: Union[str, "Protocol"] | None = None
|
870
|
+
) -> int | None:
|
876
871
|
"""The DoIP routing activation type
|
877
872
|
|
878
873
|
The number returned has the following meaning:
|
@@ -897,8 +892,7 @@ class HierarchyElement(DiagLayer):
|
|
897
892
|
return int(result)
|
898
893
|
|
899
894
|
def get_tester_present_time(self,
|
900
|
-
protocol:
|
901
|
-
"Protocol"]] = None) -> Optional[float]:
|
895
|
+
protocol: Union[str, "Protocol"] | None = None) -> float | None:
|
902
896
|
"""Timeout on inactivity in seconds.
|
903
897
|
|
904
898
|
This is defined by the communication parameter "CP_TesterPresentTime".
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import Any
|
3
|
+
from typing import Any
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from ..comparaminstance import ComparamInstance
|
@@ -17,11 +17,11 @@ class HierarchyElementRaw(DiagLayerRaw):
|
|
17
17
|
This class represents the data present in the XML, not the "logical" view.
|
18
18
|
"""
|
19
19
|
|
20
|
-
comparam_refs:
|
20
|
+
comparam_refs: list[ComparamInstance]
|
21
21
|
|
22
22
|
@staticmethod
|
23
23
|
def from_et(et_element: ElementTree.Element,
|
24
|
-
doc_frags:
|
24
|
+
doc_frags: list[OdxDocFragment]) -> "HierarchyElementRaw":
|
25
25
|
# objects contained by diagnostic layers exibit an additional
|
26
26
|
# document fragment for the diag layer, so we use the document
|
27
27
|
# fragments of the odx id of the diag layer for IDs of
|
@@ -37,7 +37,7 @@ class HierarchyElementRaw(DiagLayerRaw):
|
|
37
37
|
|
38
38
|
return HierarchyElementRaw(comparam_refs=comparam_refs, **kwargs)
|
39
39
|
|
40
|
-
def _build_odxlinks(self) ->
|
40
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
41
41
|
result = super()._build_odxlinks()
|
42
42
|
|
43
43
|
for comparam_ref in self.comparam_refs:
|
odxtools/diaglayers/protocol.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from copy import deepcopy
|
3
3
|
from dataclasses import dataclass
|
4
|
-
from typing import Any,
|
4
|
+
from typing import Any, cast
|
5
5
|
from xml.etree import ElementTree
|
6
6
|
|
7
7
|
from ..comparamspec import ComparamSpec
|
@@ -29,11 +29,11 @@ class Protocol(HierarchyElement):
|
|
29
29
|
return self.protocol_raw.comparam_spec
|
30
30
|
|
31
31
|
@property
|
32
|
-
def prot_stack(self) ->
|
32
|
+
def prot_stack(self) -> ProtStack | None:
|
33
33
|
return self.protocol_raw.prot_stack
|
34
34
|
|
35
35
|
@staticmethod
|
36
|
-
def from_et(et_element: ElementTree.Element, doc_frags:
|
36
|
+
def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "Protocol":
|
37
37
|
protocol_raw = ProtocolRaw.from_et(et_element, doc_frags)
|
38
38
|
|
39
39
|
return Protocol(diag_layer_raw=protocol_raw)
|
@@ -46,7 +46,7 @@ class Protocol(HierarchyElement):
|
|
46
46
|
"The raw diagnostic layer passed to Protocol "
|
47
47
|
"must be a ProtocolRaw")
|
48
48
|
|
49
|
-
def __deepcopy__(self, memo:
|
49
|
+
def __deepcopy__(self, memo: dict[int, Any]) -> Any:
|
50
50
|
"""Create a deep copy of the protocol layer
|
51
51
|
|
52
52
|
Note that the copied diagnostic layer is not fully
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import Any
|
3
|
+
from typing import Any
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from ..comparamspec import ComparamSpec
|
@@ -24,19 +24,19 @@ class ProtocolRaw(HierarchyElementRaw):
|
|
24
24
|
"""
|
25
25
|
|
26
26
|
comparam_spec_ref: OdxLinkRef
|
27
|
-
prot_stack_snref:
|
28
|
-
parent_refs:
|
27
|
+
prot_stack_snref: str | None
|
28
|
+
parent_refs: list[ParentRef]
|
29
29
|
|
30
30
|
@property
|
31
31
|
def comparam_spec(self) -> ComparamSpec:
|
32
32
|
return self._comparam_spec
|
33
33
|
|
34
34
|
@property
|
35
|
-
def prot_stack(self) ->
|
35
|
+
def prot_stack(self) -> ProtStack | None:
|
36
36
|
return self._prot_stack
|
37
37
|
|
38
38
|
@staticmethod
|
39
|
-
def from_et(et_element: ElementTree.Element, doc_frags:
|
39
|
+
def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "ProtocolRaw":
|
40
40
|
# objects contained by diagnostic layers exibit an additional
|
41
41
|
# document fragment for the diag layer, so we use the document
|
42
42
|
# fragments of the odx id of the diag layer for IDs of
|
@@ -63,7 +63,7 @@ class ProtocolRaw(HierarchyElementRaw):
|
|
63
63
|
parent_refs=parent_refs,
|
64
64
|
**kwargs)
|
65
65
|
|
66
|
-
def _build_odxlinks(self) ->
|
66
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
67
67
|
result = super()._build_odxlinks()
|
68
68
|
|
69
69
|
for parent_ref in self.parent_refs:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import Any
|
3
|
+
from typing import Any
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .element import IdentifiableElement
|
@@ -16,12 +16,12 @@ from .utils import dataclass_fields_asdict
|
|
16
16
|
@dataclass
|
17
17
|
class DiagnosticTroubleCode(IdentifiableElement):
|
18
18
|
trouble_code: int
|
19
|
-
display_trouble_code:
|
19
|
+
display_trouble_code: str | None
|
20
20
|
text: Text
|
21
|
-
level:
|
22
|
-
sdgs:
|
21
|
+
level: int | None
|
22
|
+
sdgs: list[SpecialDataGroup]
|
23
23
|
|
24
|
-
is_temporary_raw:
|
24
|
+
is_temporary_raw: bool | None
|
25
25
|
|
26
26
|
@property
|
27
27
|
def is_temporary(self) -> bool:
|
@@ -29,7 +29,7 @@ class DiagnosticTroubleCode(IdentifiableElement):
|
|
29
29
|
|
30
30
|
@staticmethod
|
31
31
|
def from_et(et_element: ElementTree.Element,
|
32
|
-
doc_frags:
|
32
|
+
doc_frags: list[OdxDocFragment]) -> "DiagnosticTroubleCode":
|
33
33
|
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
34
34
|
|
35
35
|
trouble_code = int(odxrequire(et_element.findtext("TROUBLE-CODE")))
|
@@ -53,8 +53,8 @@ class DiagnosticTroubleCode(IdentifiableElement):
|
|
53
53
|
is_temporary_raw=is_temporary_raw,
|
54
54
|
**kwargs)
|
55
55
|
|
56
|
-
def _build_odxlinks(self) ->
|
57
|
-
result:
|
56
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
57
|
+
result: dict[OdxLinkId, Any] = {}
|
58
58
|
|
59
59
|
result[self.odx_id] = self
|
60
60
|
|
odxtools/diagservice.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from
|
4
|
-
from typing import Any, Dict, List, Optional, Union, cast
|
3
|
+
from typing import Any, cast
|
5
4
|
from xml.etree import ElementTree
|
6
5
|
|
6
|
+
from .addressing import Addressing
|
7
7
|
from .comparaminstance import ComparamInstance
|
8
8
|
from .diagcomm import DiagComm
|
9
9
|
from .exceptions import DecodeError, DecodeMismatch, odxassert, odxraise, odxrequire
|
@@ -12,112 +12,36 @@ from .nameditemlist import NamedItemList
|
|
12
12
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
13
13
|
from .odxtypes import ParameterValue, odxstr_to_bool
|
14
14
|
from .parameters.parameter import Parameter
|
15
|
+
from .posresponsesuppressible import PosResponseSuppressible
|
15
16
|
from .request import Request
|
16
17
|
from .response import Response
|
17
18
|
from .snrefcontext import SnRefContext
|
19
|
+
from .transmode import TransMode
|
18
20
|
from .utils import dataclass_fields_asdict
|
19
21
|
|
20
22
|
|
21
|
-
class Addressing(Enum):
|
22
|
-
FUNCTIONAL = "FUNCTIONAL"
|
23
|
-
PHYSICAL = "PHYSICAL"
|
24
|
-
FUNCTIONAL_OR_PHYSICAL = "FUNCTIONAL-OR-PHYSICAL"
|
25
|
-
|
26
|
-
|
27
|
-
class TransMode(Enum):
|
28
|
-
SEND_ONLY = "SEND-ONLY"
|
29
|
-
RECEIVE_ONLY = "RECEIVE-ONLY"
|
30
|
-
SEND_AND_RECEIVE = "SEND-AND-RECEIVE"
|
31
|
-
SEND_OR_RECEIVE = "SEND-OR-RECEIVE"
|
32
|
-
|
33
|
-
|
34
|
-
# note that the spec has a typo here: it calls the corresponding
|
35
|
-
# XML tag POS-RESPONSE-SUPPRESSABLE...
|
36
|
-
@dataclass
|
37
|
-
class PosResponseSuppressible:
|
38
|
-
bit_mask: int
|
39
|
-
|
40
|
-
coded_const_snref: Optional[str]
|
41
|
-
coded_const_snpathref: Optional[str]
|
42
|
-
|
43
|
-
value_snref: Optional[str]
|
44
|
-
value_snpathref: Optional[str]
|
45
|
-
|
46
|
-
phys_const_snref: Optional[str]
|
47
|
-
phys_const_snpathref: Optional[str]
|
48
|
-
|
49
|
-
table_key_snref: Optional[str]
|
50
|
-
table_key_snpathref: Optional[str]
|
51
|
-
|
52
|
-
@staticmethod
|
53
|
-
def from_et(et_element: ElementTree.Element,
|
54
|
-
doc_frags: List[OdxDocFragment]) -> "PosResponseSuppressible":
|
55
|
-
|
56
|
-
bit_mask = int(odxrequire(et_element.findtext("BIT-MASK")))
|
57
|
-
|
58
|
-
coded_const_snref = None
|
59
|
-
if (cc_snref_elem := et_element.find("CODED-CONST-SNREF")) is not None:
|
60
|
-
coded_const_snref = cc_snref_elem.attrib["SHORT-NAME"]
|
61
|
-
coded_const_snpathref = None
|
62
|
-
if (cc_snpathref_elem := et_element.find("CODED-CONST-SNPATHREF")) is not None:
|
63
|
-
coded_const_snpathref = cc_snpathref_elem.attrib["SHORT-NAME-PATH"]
|
64
|
-
|
65
|
-
value_snref = None
|
66
|
-
if (cc_snref_elem := et_element.find("VALUE-SNREF")) is not None:
|
67
|
-
value_snref = cc_snref_elem.attrib["SHORT-NAME"]
|
68
|
-
value_snpathref = None
|
69
|
-
if (cc_snpathref_elem := et_element.find("VALUE-SNPATHREF")) is not None:
|
70
|
-
value_snpathref = cc_snpathref_elem.attrib["SHORT-NAME-PATH"]
|
71
|
-
|
72
|
-
phys_const_snref = None
|
73
|
-
if (cc_snref_elem := et_element.find("PHYS-CONST-SNREF")) is not None:
|
74
|
-
phys_const_snref = cc_snref_elem.attrib["SHORT-NAME"]
|
75
|
-
phys_const_snpathref = None
|
76
|
-
if (cc_snpathref_elem := et_element.find("PHYS-CONST-SNPATHREF")) is not None:
|
77
|
-
phys_const_snpathref = cc_snpathref_elem.attrib["SHORT-NAME-PATH"]
|
78
|
-
|
79
|
-
table_key_snref = None
|
80
|
-
if (cc_snref_elem := et_element.find("TABLE-KEY-SNREF")) is not None:
|
81
|
-
table_key_snref = cc_snref_elem.attrib["SHORT-NAME"]
|
82
|
-
table_key_snpathref = None
|
83
|
-
if (cc_snpathref_elem := et_element.find("TABLE-KEY-SNPATHREF")) is not None:
|
84
|
-
table_key_snpathref = cc_snpathref_elem.attrib["SHORT-NAME-PATH"]
|
85
|
-
|
86
|
-
return PosResponseSuppressible(
|
87
|
-
bit_mask=bit_mask,
|
88
|
-
coded_const_snref=coded_const_snref,
|
89
|
-
coded_const_snpathref=coded_const_snpathref,
|
90
|
-
value_snref=value_snref,
|
91
|
-
value_snpathref=value_snpathref,
|
92
|
-
phys_const_snref=phys_const_snref,
|
93
|
-
phys_const_snpathref=phys_const_snpathref,
|
94
|
-
table_key_snref=table_key_snref,
|
95
|
-
table_key_snpathref=table_key_snpathref,
|
96
|
-
)
|
97
|
-
|
98
|
-
|
99
23
|
@dataclass
|
100
24
|
class DiagService(DiagComm):
|
101
25
|
"""Representation of a diagnostic service description.
|
102
26
|
"""
|
103
27
|
|
104
|
-
comparam_refs:
|
28
|
+
comparam_refs: list[ComparamInstance]
|
105
29
|
request_ref: OdxLinkRef
|
106
|
-
pos_response_refs:
|
107
|
-
neg_response_refs:
|
108
|
-
pos_response_suppressible:
|
30
|
+
pos_response_refs: list[OdxLinkRef]
|
31
|
+
neg_response_refs: list[OdxLinkRef]
|
32
|
+
pos_response_suppressible: PosResponseSuppressible | None
|
109
33
|
|
110
|
-
is_cyclic_raw:
|
111
|
-
is_multiple_raw:
|
112
|
-
addressing_raw:
|
113
|
-
transmission_mode_raw:
|
34
|
+
is_cyclic_raw: bool | None
|
35
|
+
is_multiple_raw: bool | None
|
36
|
+
addressing_raw: Addressing | None
|
37
|
+
transmission_mode_raw: TransMode | None
|
114
38
|
|
115
39
|
@property
|
116
40
|
def comparams(self) -> NamedItemList[ComparamInstance]:
|
117
41
|
return self._comparams
|
118
42
|
|
119
43
|
@property
|
120
|
-
def request(self) ->
|
44
|
+
def request(self) -> Request | None:
|
121
45
|
return self._request
|
122
46
|
|
123
47
|
@property
|
@@ -145,14 +69,14 @@ class DiagService(DiagComm):
|
|
145
69
|
return self.transmission_mode_raw or TransMode.SEND_AND_RECEIVE
|
146
70
|
|
147
71
|
@property
|
148
|
-
def free_parameters(self) ->
|
72
|
+
def free_parameters(self) -> list[Parameter]:
|
149
73
|
"""Return the list of parameters which can be freely specified by
|
150
74
|
the user when encoding the service's request.
|
151
75
|
"""
|
152
76
|
return self.request.free_parameters if self.request is not None else []
|
153
77
|
|
154
78
|
@staticmethod
|
155
|
-
def from_et(et_element: ElementTree.Element, doc_frags:
|
79
|
+
def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "DiagService":
|
156
80
|
|
157
81
|
kwargs = dataclass_fields_asdict(DiagComm.from_et(et_element, doc_frags))
|
158
82
|
|
@@ -180,7 +104,7 @@ class DiagService(DiagComm):
|
|
180
104
|
is_cyclic_raw = odxstr_to_bool(et_element.get("IS-CYCLIC"))
|
181
105
|
is_multiple_raw = odxstr_to_bool(et_element.get("IS-MULTIPLE"))
|
182
106
|
|
183
|
-
addressing_raw:
|
107
|
+
addressing_raw: Addressing | None = None
|
184
108
|
if (addressing_raw_str := et_element.get("ADDRESSING")) is not None:
|
185
109
|
try:
|
186
110
|
addressing_raw = Addressing(addressing_raw_str)
|
@@ -188,7 +112,7 @@ class DiagService(DiagComm):
|
|
188
112
|
addressing_raw = cast(Addressing, None)
|
189
113
|
odxraise(f"Encountered unknown addressing type '{addressing_raw_str}'")
|
190
114
|
|
191
|
-
transmission_mode_raw:
|
115
|
+
transmission_mode_raw: TransMode | None = None
|
192
116
|
if (transmission_mode_raw_str := et_element.get("TRANSMISSION-MODE")) is not None:
|
193
117
|
try:
|
194
118
|
transmission_mode_raw = TransMode(transmission_mode_raw_str)
|
@@ -208,7 +132,7 @@ class DiagService(DiagComm):
|
|
208
132
|
transmission_mode_raw=transmission_mode_raw,
|
209
133
|
**kwargs)
|
210
134
|
|
211
|
-
def _build_odxlinks(self) ->
|
135
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
212
136
|
result = super()._build_odxlinks()
|
213
137
|
|
214
138
|
for cpr in self.comparam_refs:
|
@@ -256,20 +180,20 @@ class DiagService(DiagComm):
|
|
256
180
|
|
257
181
|
def decode_message(self, raw_message: bytes) -> Message:
|
258
182
|
request_prefix = b''
|
259
|
-
candidate_coding_objects:
|
183
|
+
candidate_coding_objects: list[Request | Response] = [
|
260
184
|
*self.positive_responses, *self.negative_responses
|
261
185
|
]
|
262
186
|
if self.request is not None:
|
263
187
|
request_prefix = self.request.coded_const_prefix()
|
264
188
|
candidate_coding_objects.append(self.request)
|
265
189
|
|
266
|
-
coding_objects:
|
190
|
+
coding_objects: list[Request | Response] = []
|
267
191
|
for candidate_coding_object in candidate_coding_objects:
|
268
192
|
prefix = candidate_coding_object.coded_const_prefix(request_prefix=request_prefix)
|
269
193
|
if len(raw_message) >= len(prefix) and prefix == raw_message[:len(prefix)]:
|
270
194
|
coding_objects.append(candidate_coding_object)
|
271
195
|
|
272
|
-
result_list:
|
196
|
+
result_list: list[Message] = []
|
273
197
|
for coding_object in coding_objects:
|
274
198
|
try:
|
275
199
|
result_list.append(
|