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
@@ -0,0 +1,58 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Any, Dict, List
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from ..comparaminstance import ComparamInstance
|
7
|
+
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
8
|
+
from ..snrefcontext import SnRefContext
|
9
|
+
from ..utils import dataclass_fields_asdict
|
10
|
+
from .diaglayerraw import DiagLayerRaw
|
11
|
+
|
12
|
+
|
13
|
+
@dataclass
|
14
|
+
class HierarchyElementRaw(DiagLayerRaw):
|
15
|
+
"""This is the base class for diagnostic layers that may be involved in value inheritance
|
16
|
+
|
17
|
+
This class represents the data present in the XML, not the "logical" view.
|
18
|
+
"""
|
19
|
+
|
20
|
+
comparam_refs: List[ComparamInstance]
|
21
|
+
|
22
|
+
@staticmethod
|
23
|
+
def from_et(et_element: ElementTree.Element,
|
24
|
+
doc_frags: List[OdxDocFragment]) -> "HierarchyElementRaw":
|
25
|
+
# objects contained by diagnostic layers exibit an additional
|
26
|
+
# document fragment for the diag layer, so we use the document
|
27
|
+
# fragments of the odx id of the diag layer for IDs of
|
28
|
+
# contained objects.
|
29
|
+
dlr = DiagLayerRaw.from_et(et_element, doc_frags)
|
30
|
+
kwargs = dataclass_fields_asdict(dlr)
|
31
|
+
doc_frags = dlr.odx_id.doc_fragments
|
32
|
+
|
33
|
+
comparam_refs = [
|
34
|
+
ComparamInstance.from_et(el, doc_frags)
|
35
|
+
for el in et_element.iterfind("COMPARAM-REFS/COMPARAM-REF")
|
36
|
+
]
|
37
|
+
|
38
|
+
return HierarchyElementRaw(comparam_refs=comparam_refs, **kwargs)
|
39
|
+
|
40
|
+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
41
|
+
result = super()._build_odxlinks()
|
42
|
+
|
43
|
+
for comparam_ref in self.comparam_refs:
|
44
|
+
result.update(comparam_ref._build_odxlinks())
|
45
|
+
|
46
|
+
return result
|
47
|
+
|
48
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
49
|
+
super()._resolve_odxlinks(odxlinks)
|
50
|
+
|
51
|
+
for comparam_ref in self.comparam_refs:
|
52
|
+
comparam_ref._resolve_odxlinks(odxlinks)
|
53
|
+
|
54
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
55
|
+
super()._resolve_snrefs(context)
|
56
|
+
|
57
|
+
for comparam_ref in self.comparam_refs:
|
58
|
+
comparam_ref._resolve_snrefs(context)
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from copy import deepcopy
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from typing import Any, Dict, List, Optional, cast
|
5
|
+
from xml.etree import ElementTree
|
6
|
+
|
7
|
+
from ..comparamspec import ComparamSpec
|
8
|
+
from ..exceptions import odxassert
|
9
|
+
from ..odxlink import OdxDocFragment
|
10
|
+
from ..protstack import ProtStack
|
11
|
+
from .hierarchyelement import HierarchyElement
|
12
|
+
from .protocolraw import ProtocolRaw
|
13
|
+
|
14
|
+
|
15
|
+
@dataclass
|
16
|
+
class Protocol(HierarchyElement):
|
17
|
+
"""This is the class for primitives that are common for a given communication protocol
|
18
|
+
|
19
|
+
Most importantly this diagnostic layer is responsible for defining
|
20
|
+
the communication parameters that ought to be used.
|
21
|
+
"""
|
22
|
+
|
23
|
+
@property
|
24
|
+
def protocol_raw(self) -> ProtocolRaw:
|
25
|
+
return cast(ProtocolRaw, self.diag_layer_raw)
|
26
|
+
|
27
|
+
@property
|
28
|
+
def comparam_spec(self) -> ComparamSpec:
|
29
|
+
return self.protocol_raw.comparam_spec
|
30
|
+
|
31
|
+
@property
|
32
|
+
def prot_stack(self) -> Optional[ProtStack]:
|
33
|
+
return self.protocol_raw.prot_stack
|
34
|
+
|
35
|
+
@staticmethod
|
36
|
+
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Protocol":
|
37
|
+
protocol_raw = ProtocolRaw.from_et(et_element, doc_frags)
|
38
|
+
|
39
|
+
return Protocol(diag_layer_raw=protocol_raw)
|
40
|
+
|
41
|
+
def __post_init__(self) -> None:
|
42
|
+
super().__post_init__()
|
43
|
+
|
44
|
+
odxassert(
|
45
|
+
isinstance(self.diag_layer_raw, ProtocolRaw),
|
46
|
+
"The raw diagnostic layer passed to Protocol "
|
47
|
+
"must be a ProtocolRaw")
|
48
|
+
|
49
|
+
def __deepcopy__(self, memo: Dict[int, Any]) -> Any:
|
50
|
+
"""Create a deep copy of the protocol layer
|
51
|
+
|
52
|
+
Note that the copied diagnostic layer is not fully
|
53
|
+
initialized, so `_finalize_init()` should to be called on it
|
54
|
+
before it can be used normally.
|
55
|
+
"""
|
56
|
+
|
57
|
+
result = super().__deepcopy__(memo)
|
58
|
+
|
59
|
+
# note that the self.protocol_raw object is *not* copied at
|
60
|
+
# this place because the attribute points to the same object
|
61
|
+
# as self.diag_layer_raw.
|
62
|
+
result.protocol_raw = deepcopy(self.protocol_raw, memo)
|
63
|
+
|
64
|
+
return result
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from ..comparamspec import ComparamSpec
|
7
|
+
from ..exceptions import odxrequire
|
8
|
+
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
9
|
+
from ..parentref import ParentRef
|
10
|
+
from ..protstack import ProtStack
|
11
|
+
from ..snrefcontext import SnRefContext
|
12
|
+
from ..utils import dataclass_fields_asdict
|
13
|
+
#from .comparaminstance import ComparamInstance
|
14
|
+
from .hierarchyelementraw import HierarchyElementRaw
|
15
|
+
|
16
|
+
|
17
|
+
@dataclass
|
18
|
+
class ProtocolRaw(HierarchyElementRaw):
|
19
|
+
"""This is the base class for diagnostic layers that describe a
|
20
|
+
protocol which can be used to communicate with an ECU
|
21
|
+
|
22
|
+
This class represents the data present in the XML, not the "logical" view.
|
23
|
+
|
24
|
+
"""
|
25
|
+
|
26
|
+
comparam_spec_ref: OdxLinkRef
|
27
|
+
prot_stack_snref: Optional[str]
|
28
|
+
parent_refs: List[ParentRef]
|
29
|
+
|
30
|
+
@property
|
31
|
+
def comparam_spec(self) -> ComparamSpec:
|
32
|
+
return self._comparam_spec
|
33
|
+
|
34
|
+
@property
|
35
|
+
def prot_stack(self) -> Optional[ProtStack]:
|
36
|
+
return self._prot_stack
|
37
|
+
|
38
|
+
@staticmethod
|
39
|
+
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "ProtocolRaw":
|
40
|
+
# objects contained by diagnostic layers exibit an additional
|
41
|
+
# document fragment for the diag layer, so we use the document
|
42
|
+
# fragments of the odx id of the diag layer for IDs of
|
43
|
+
# contained objects.
|
44
|
+
her = HierarchyElementRaw.from_et(et_element, doc_frags)
|
45
|
+
kwargs = dataclass_fields_asdict(her)
|
46
|
+
doc_frags = her.odx_id.doc_fragments
|
47
|
+
|
48
|
+
comparam_spec_ref = OdxLinkRef.from_et(
|
49
|
+
odxrequire(et_element.find("COMPARAM-SPEC-REF")), doc_frags)
|
50
|
+
|
51
|
+
prot_stack_snref = None
|
52
|
+
if (prot_stack_snref_elem := et_element.find("PROT-STACK-SNREF")) is not None:
|
53
|
+
prot_stack_snref = odxrequire(prot_stack_snref_elem.get("SHORT-NAME"))
|
54
|
+
|
55
|
+
parent_refs = [
|
56
|
+
ParentRef.from_et(pr_el, doc_frags)
|
57
|
+
for pr_el in et_element.iterfind("PARENT-REFS/PARENT-REF")
|
58
|
+
]
|
59
|
+
|
60
|
+
return ProtocolRaw(
|
61
|
+
comparam_spec_ref=comparam_spec_ref,
|
62
|
+
prot_stack_snref=prot_stack_snref,
|
63
|
+
parent_refs=parent_refs,
|
64
|
+
**kwargs)
|
65
|
+
|
66
|
+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
67
|
+
result = super()._build_odxlinks()
|
68
|
+
|
69
|
+
for parent_ref in self.parent_refs:
|
70
|
+
result.update(parent_ref._build_odxlinks())
|
71
|
+
|
72
|
+
return result
|
73
|
+
|
74
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
75
|
+
super()._resolve_odxlinks(odxlinks)
|
76
|
+
|
77
|
+
for parent_ref in self.parent_refs:
|
78
|
+
parent_ref._resolve_odxlinks(odxlinks)
|
79
|
+
|
80
|
+
self._comparam_spec = odxlinks.resolve(self.comparam_spec_ref, ComparamSpec)
|
81
|
+
|
82
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
83
|
+
super()._resolve_snrefs(context)
|
84
|
+
|
85
|
+
self._prot_stack = None
|
86
|
+
if self.prot_stack_snref is not None:
|
87
|
+
self._prot_stack = resolve_snref(self.prot_stack_snref, self._comparam_spec.prot_stacks,
|
88
|
+
ProtStack)
|
89
|
+
|
90
|
+
for parent_ref in self.parent_refs:
|
91
|
+
parent_ref._resolve_snrefs(context)
|
@@ -1,26 +1,23 @@
|
|
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 .createsdgs import create_sdgs_from_et
|
7
6
|
from .element import IdentifiableElement
|
8
7
|
from .exceptions import odxrequire
|
9
8
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
10
9
|
from .odxtypes import odxstr_to_bool
|
10
|
+
from .snrefcontext import SnRefContext
|
11
11
|
from .specialdatagroup import SpecialDataGroup
|
12
12
|
from .utils import dataclass_fields_asdict
|
13
13
|
|
14
|
-
if TYPE_CHECKING:
|
15
|
-
from .diaglayer import DiagLayer
|
16
|
-
|
17
14
|
|
18
15
|
@dataclass
|
19
16
|
class DiagnosticTroubleCode(IdentifiableElement):
|
20
17
|
trouble_code: int
|
21
18
|
text: Optional[str]
|
22
19
|
display_trouble_code: Optional[str]
|
23
|
-
level:
|
20
|
+
level: Optional[int]
|
24
21
|
is_temporary_raw: Optional[bool]
|
25
22
|
sdgs: List[SpecialDataGroup]
|
26
23
|
|
@@ -43,7 +40,9 @@ class DiagnosticTroubleCode(IdentifiableElement):
|
|
43
40
|
level = None
|
44
41
|
|
45
42
|
is_temporary_raw = odxstr_to_bool(et_element.get("IS-TEMPORARY"))
|
46
|
-
sdgs =
|
43
|
+
sdgs = [
|
44
|
+
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
45
|
+
]
|
47
46
|
|
48
47
|
return DiagnosticTroubleCode(
|
49
48
|
trouble_code=int(odxrequire(et_element.findtext("TROUBLE-CODE"))),
|
@@ -69,6 +68,6 @@ class DiagnosticTroubleCode(IdentifiableElement):
|
|
69
68
|
for sdg in self.sdgs:
|
70
69
|
sdg._resolve_odxlinks(odxlinks)
|
71
70
|
|
72
|
-
def _resolve_snrefs(self,
|
71
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
73
72
|
for sdg in self.sdgs:
|
74
|
-
sdg._resolve_snrefs(
|
73
|
+
sdg._resolve_snrefs(context)
|
odxtools/diagservice.py
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from enum import Enum
|
4
|
-
from typing import
|
4
|
+
from typing import Any, Dict, List, Optional, Union, cast
|
5
5
|
from xml.etree import ElementTree
|
6
6
|
|
7
7
|
from .comparaminstance import ComparamInstance
|
8
8
|
from .diagcomm import DiagComm
|
9
|
-
from .exceptions import DecodeError, odxassert, odxraise, odxrequire
|
9
|
+
from .exceptions import DecodeError, DecodeMismatch, odxassert, odxraise, odxrequire
|
10
10
|
from .message import Message
|
11
11
|
from .nameditemlist import NamedItemList
|
12
12
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
@@ -14,11 +14,9 @@ from .odxtypes import ParameterValue, odxstr_to_bool
|
|
14
14
|
from .parameters.parameter import Parameter
|
15
15
|
from .request import Request
|
16
16
|
from .response import Response
|
17
|
+
from .snrefcontext import SnRefContext
|
17
18
|
from .utils import dataclass_fields_asdict
|
18
19
|
|
19
|
-
if TYPE_CHECKING:
|
20
|
-
from .diaglayer import DiagLayer
|
21
|
-
|
22
20
|
|
23
21
|
class Addressing(Enum):
|
24
22
|
FUNCTIONAL = "FUNCTIONAL"
|
@@ -44,7 +42,9 @@ class DiagService(DiagComm):
|
|
44
42
|
pos_response_refs: List[OdxLinkRef]
|
45
43
|
neg_response_refs: List[OdxLinkRef]
|
46
44
|
|
47
|
-
#
|
45
|
+
# note that the spec has a typo here: it calls the corresponding
|
46
|
+
# XML tag POS-RESPONSE-SUPPRESSABLE...
|
47
|
+
# TODO: pos_response_suppressible: Optional[PosResponseSuppressible]
|
48
48
|
|
49
49
|
is_cyclic_raw: Optional[bool]
|
50
50
|
is_multiple_raw: Optional[bool]
|
@@ -167,7 +167,7 @@ class DiagService(DiagComm):
|
|
167
167
|
for cpr in self.comparam_refs:
|
168
168
|
cpr._resolve_odxlinks(odxlinks)
|
169
169
|
|
170
|
-
self._request = odxlinks.resolve(self.request_ref)
|
170
|
+
self._request = odxlinks.resolve(self.request_ref, Request)
|
171
171
|
|
172
172
|
self._positive_responses = NamedItemList[Response](
|
173
173
|
[odxlinks.resolve(x, Response) for x in self.pos_response_refs])
|
@@ -175,16 +175,21 @@ class DiagService(DiagComm):
|
|
175
175
|
self._negative_responses = NamedItemList[Response](
|
176
176
|
[odxlinks.resolve(x, Response) for x in self.neg_response_refs])
|
177
177
|
|
178
|
-
def _resolve_snrefs(self,
|
179
|
-
|
178
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
179
|
+
context.diag_service = self
|
180
|
+
|
181
|
+
super()._resolve_snrefs(context)
|
180
182
|
|
181
183
|
for cpr in self.comparam_refs:
|
182
|
-
cpr._resolve_snrefs(
|
184
|
+
cpr._resolve_snrefs(context)
|
183
185
|
|
184
|
-
#
|
185
|
-
#
|
186
|
+
# The named item list of communication parameters is created
|
187
|
+
# here because ComparamInstance.short_name is only valid after
|
188
|
+
# reference resolution
|
186
189
|
self._comparams = NamedItemList(self.comparam_refs)
|
187
190
|
|
191
|
+
context.diag_service = None
|
192
|
+
|
188
193
|
def decode_message(self, raw_message: bytes) -> Message:
|
189
194
|
request_prefix = b''
|
190
195
|
candidate_coding_objects: List[Union[Request, Response]] = [
|
@@ -200,28 +205,36 @@ class DiagService(DiagComm):
|
|
200
205
|
if len(raw_message) >= len(prefix) and prefix == raw_message[:len(prefix)]:
|
201
206
|
coding_objects.append(candidate_coding_object)
|
202
207
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
208
|
+
result_list: List[Message] = []
|
209
|
+
for coding_object in coding_objects:
|
210
|
+
try:
|
211
|
+
result_list.append(
|
212
|
+
Message(
|
213
|
+
coded_message=raw_message,
|
214
|
+
service=self,
|
215
|
+
coding_object=coding_object,
|
216
|
+
param_dict=coding_object.decode(raw_message)))
|
217
|
+
except DecodeMismatch:
|
218
|
+
# An NRC-CONST or environment data parameter
|
219
|
+
# encountered a non-matching value -> coding object
|
220
|
+
# does not apply
|
221
|
+
pass
|
222
|
+
|
223
|
+
if len(result_list) < 1:
|
224
|
+
odxraise(f"The service {self.short_name} cannot decode the message {raw_message.hex()}",
|
225
|
+
DecodeError)
|
226
|
+
return Message(
|
227
|
+
coded_message=raw_message, service=self, coding_object=None, param_dict={})
|
228
|
+
elif len(result_list) > 1:
|
229
|
+
odxraise(
|
230
|
+
f"The service {self.short_name} cannot uniquely decode the message {raw_message.hex()}",
|
231
|
+
DecodeError)
|
232
|
+
|
233
|
+
return result_list[0]
|
234
|
+
|
235
|
+
def encode_request(self, **kwargs: ParameterValue) -> bytes:
|
236
|
+
"""Prepare an array of bytes ready to be send over the wire
|
237
|
+
for the request of this service.
|
225
238
|
"""
|
226
239
|
# make sure that all parameters which are required for
|
227
240
|
# encoding are specified (parameters which have a default are
|
@@ -230,31 +243,31 @@ class DiagService(DiagComm):
|
|
230
243
|
return b''
|
231
244
|
|
232
245
|
missing_params = {x.short_name
|
233
|
-
for x in self.request.required_parameters}.difference(
|
246
|
+
for x in self.request.required_parameters}.difference(kwargs.keys())
|
234
247
|
odxassert(
|
235
248
|
len(missing_params) == 0, f"The parameters {missing_params} are required but missing!")
|
236
249
|
|
237
250
|
# make sure that no unknown parameters are specified
|
238
251
|
rq_all_param_names = {x.short_name for x in self.request.parameters}
|
239
252
|
odxassert(
|
240
|
-
set(
|
241
|
-
f"Unknown parameters specified for encoding: {
|
253
|
+
set(kwargs.keys()).issubset(rq_all_param_names),
|
254
|
+
f"Unknown parameters specified for encoding: {kwargs.keys()}, "
|
242
255
|
f"known parameters are: {rq_all_param_names}")
|
243
|
-
return self.request.encode(
|
256
|
+
return self.request.encode(**kwargs)
|
244
257
|
|
245
258
|
def encode_positive_response(self,
|
246
259
|
coded_request: bytes,
|
247
260
|
response_index: int = 0,
|
248
|
-
**
|
261
|
+
**kwargs: ParameterValue) -> bytes:
|
249
262
|
# TODO: Should the user decide the positive response or what are the differences?
|
250
|
-
return self.positive_responses[response_index].encode(coded_request, **
|
263
|
+
return self.positive_responses[response_index].encode(coded_request, **kwargs)
|
251
264
|
|
252
265
|
def encode_negative_response(self,
|
253
266
|
coded_request: bytes,
|
254
267
|
response_index: int = 0,
|
255
|
-
**
|
256
|
-
return self.negative_responses[response_index].encode(coded_request, **
|
268
|
+
**kwargs: ParameterValue) -> bytes:
|
269
|
+
return self.negative_responses[response_index].encode(coded_request, **kwargs)
|
257
270
|
|
258
|
-
def __call__(self, **
|
271
|
+
def __call__(self, **kwargs: ParameterValue) -> bytes:
|
259
272
|
"""Encode a request."""
|
260
|
-
return self.encode_request(**
|
273
|
+
return self.encode_request(**kwargs)
|
odxtools/diagvariable.py
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
import typing
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from typing import Any, Dict, List, Optional, runtime_checkable
|
5
|
+
from xml.etree import ElementTree
|
6
|
+
|
7
|
+
from .admindata import AdminData
|
8
|
+
from .commrelation import CommRelation
|
9
|
+
from .element import IdentifiableElement
|
10
|
+
from .exceptions import odxrequire
|
11
|
+
from .nameditemlist import NamedItemList
|
12
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
13
|
+
from .odxtypes import odxstr_to_bool
|
14
|
+
from .snrefcontext import SnRefContext
|
15
|
+
from .specialdatagroup import SpecialDataGroup
|
16
|
+
from .swvariable import SwVariable
|
17
|
+
from .utils import dataclass_fields_asdict
|
18
|
+
from .variablegroup import VariableGroup
|
19
|
+
|
20
|
+
|
21
|
+
@runtime_checkable
|
22
|
+
class HasDiagVariables(typing.Protocol):
|
23
|
+
|
24
|
+
@property
|
25
|
+
def diag_variables(self) -> "NamedItemList[DiagVariable]":
|
26
|
+
...
|
27
|
+
|
28
|
+
|
29
|
+
@dataclass
|
30
|
+
class DiagVariable(IdentifiableElement):
|
31
|
+
"""Representation of a diagnostic variable
|
32
|
+
"""
|
33
|
+
|
34
|
+
admin_data: Optional[AdminData]
|
35
|
+
variable_group_ref: OdxLinkRef
|
36
|
+
sw_variables: List[SwVariable]
|
37
|
+
comm_relations: List[CommRelation]
|
38
|
+
#snref_to_tablerow: Optional[SnrefToTableRow] # TODO
|
39
|
+
sdgs: List[SpecialDataGroup]
|
40
|
+
is_read_before_write_raw: Optional[bool]
|
41
|
+
|
42
|
+
@property
|
43
|
+
def variable_group(self) -> VariableGroup:
|
44
|
+
return self._variable_group
|
45
|
+
|
46
|
+
@property
|
47
|
+
def is_read_before_write(self) -> bool:
|
48
|
+
return self.is_read_before_write_raw is True
|
49
|
+
|
50
|
+
@staticmethod
|
51
|
+
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DiagVariable":
|
52
|
+
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
53
|
+
|
54
|
+
admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
|
55
|
+
variable_group_ref = odxrequire(
|
56
|
+
OdxLinkRef.from_et(et_element.find("VARIABLE-GROUP-REF"), doc_frags))
|
57
|
+
sw_variables = NamedItemList([
|
58
|
+
SwVariable.from_et(swv_elem, doc_frags)
|
59
|
+
for swv_elem in et_element.iterfind("SW-VARIABLES/SW-VARIABLE")
|
60
|
+
])
|
61
|
+
comm_relations = [
|
62
|
+
CommRelation.from_et(cr_elem, doc_frags)
|
63
|
+
for cr_elem in et_element.iterfind("COMM-RELATIONS/COMM-RELATION")
|
64
|
+
]
|
65
|
+
sdgs = [
|
66
|
+
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
67
|
+
]
|
68
|
+
is_read_before_write_raw = odxstr_to_bool(et_element.get("IS-READ-BEFORE-WRITE"))
|
69
|
+
|
70
|
+
return DiagVariable(
|
71
|
+
admin_data=admin_data,
|
72
|
+
variable_group_ref=variable_group_ref,
|
73
|
+
sw_variables=sw_variables,
|
74
|
+
comm_relations=comm_relations,
|
75
|
+
sdgs=sdgs,
|
76
|
+
is_read_before_write_raw=is_read_before_write_raw,
|
77
|
+
**kwargs)
|
78
|
+
|
79
|
+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
80
|
+
result = {self.odx_id: self}
|
81
|
+
|
82
|
+
if self.admin_data is not None:
|
83
|
+
result.update(self.admin_data._build_odxlinks())
|
84
|
+
|
85
|
+
for sdg in self.sdgs:
|
86
|
+
result.update(sdg._build_odxlinks())
|
87
|
+
|
88
|
+
for cr in self.comm_relations:
|
89
|
+
result.update(cr._build_odxlinks())
|
90
|
+
|
91
|
+
return result
|
92
|
+
|
93
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
94
|
+
self._variable_group = odxlinks.resolve(self.variable_group_ref, VariableGroup)
|
95
|
+
|
96
|
+
if self.admin_data is not None:
|
97
|
+
self.admin_data._resolve_odxlinks(odxlinks)
|
98
|
+
|
99
|
+
for sdg in self.sdgs:
|
100
|
+
sdg._resolve_odxlinks(odxlinks)
|
101
|
+
|
102
|
+
for cr in self.comm_relations:
|
103
|
+
cr._resolve_odxlinks(odxlinks)
|
104
|
+
|
105
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
106
|
+
if self.admin_data is not None:
|
107
|
+
self.admin_data._resolve_snrefs(context)
|
108
|
+
|
109
|
+
for sdg in self.sdgs:
|
110
|
+
sdg._resolve_snrefs(context)
|
111
|
+
|
112
|
+
for cr in self.comm_relations:
|
113
|
+
cr._resolve_snrefs(context)
|
odxtools/docrevision.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, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .companyrevisioninfo import CompanyRevisionInfo
|
7
7
|
from .exceptions import odxrequire
|
8
8
|
from .modification import Modification
|
9
9
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
10
|
+
from .snrefcontext import SnRefContext
|
10
11
|
from .teammember import TeamMember
|
11
12
|
|
12
|
-
if TYPE_CHECKING:
|
13
|
-
from .diaglayer import DiagLayer
|
14
|
-
|
15
13
|
|
16
14
|
@dataclass
|
17
15
|
class DocRevision:
|
@@ -75,9 +73,9 @@ class DocRevision:
|
|
75
73
|
for mod in self.modifications:
|
76
74
|
mod._resolve_odxlinks(odxlinks)
|
77
75
|
|
78
|
-
def _resolve_snrefs(self,
|
76
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
79
77
|
for cri in self.company_revision_infos:
|
80
|
-
cri._resolve_snrefs(
|
78
|
+
cri._resolve_snrefs(context)
|
81
79
|
|
82
80
|
for mod in self.modifications:
|
83
|
-
mod._resolve_snrefs(
|
81
|
+
mod._resolve_snrefs(context)
|
odxtools/dopbase.py
CHANGED
@@ -1,27 +1,27 @@
|
|
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 .admindata import AdminData
|
7
|
-
from .createsdgs import create_sdgs_from_et
|
8
7
|
from .decodestate import DecodeState
|
9
8
|
from .element import IdentifiableElement
|
10
9
|
from .encodestate import EncodeState
|
11
10
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
12
11
|
from .odxtypes import ParameterValue
|
12
|
+
from .snrefcontext import SnRefContext
|
13
13
|
from .specialdatagroup import SpecialDataGroup
|
14
14
|
from .utils import dataclass_fields_asdict
|
15
15
|
|
16
|
-
if TYPE_CHECKING:
|
17
|
-
from .diaglayer import DiagLayer
|
18
|
-
|
19
16
|
|
20
17
|
@dataclass
|
21
18
|
class DopBase(IdentifiableElement):
|
22
|
-
"""Base class for all
|
19
|
+
"""Base class for all (simple and complex) data object properties.
|
20
|
+
|
21
|
+
Any class that a parameter can reference via a DOP-REF (Simple
|
22
|
+
DOPs, structures, ...) inherits from this class. All DOPs objects
|
23
|
+
implement the `Codec` type protocol.
|
23
24
|
|
24
|
-
Any class that a parameter can reference via a DOP-REF should inherit from this class.
|
25
25
|
"""
|
26
26
|
|
27
27
|
admin_data: Optional[AdminData]
|
@@ -36,7 +36,9 @@ class DopBase(IdentifiableElement):
|
|
36
36
|
if (admin_data_elem := et_element.find("ADMIN-DATA")) is not None:
|
37
37
|
admin_data = AdminData.from_et(admin_data_elem, doc_frags)
|
38
38
|
|
39
|
-
sdgs =
|
39
|
+
sdgs = [
|
40
|
+
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
41
|
+
]
|
40
42
|
|
41
43
|
return DopBase(admin_data=admin_data, sdgs=sdgs, **kwargs)
|
42
44
|
|
@@ -52,21 +54,19 @@ class DopBase(IdentifiableElement):
|
|
52
54
|
for sdg in self.sdgs:
|
53
55
|
sdg._resolve_odxlinks(odxlinks)
|
54
56
|
|
55
|
-
def _resolve_snrefs(self,
|
57
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
56
58
|
for sdg in self.sdgs:
|
57
|
-
sdg._resolve_snrefs(
|
59
|
+
sdg._resolve_snrefs(context)
|
58
60
|
|
59
61
|
def get_static_bit_length(self) -> Optional[int]:
|
60
62
|
return None
|
61
63
|
|
62
64
|
def is_valid_physical_value(self, physical_value: ParameterValue) -> bool:
|
63
|
-
"""Determine if a phyical value can be handled by the DOP
|
64
|
-
"""
|
65
|
+
"""Determine if a phyical value can be handled by the DOP"""
|
65
66
|
raise NotImplementedError
|
66
67
|
|
67
|
-
def
|
68
|
-
|
69
|
-
"""Convert the physical value into bytes."""
|
68
|
+
def encode_into_pdu(self, physical_value: ParameterValue, encode_state: EncodeState) -> None:
|
69
|
+
"""Convert the physical value to bytes and emplace them into a PDU."""
|
70
70
|
raise NotImplementedError
|
71
71
|
|
72
72
|
def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|