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
@@ -0,0 +1,161 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Any
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from .diagclasstype import DiagClassType
|
7
|
+
from .diagcomm import DiagComm
|
8
|
+
from .exceptions import odxassert, odxraise, odxrequire
|
9
|
+
from .nameditemlist import NamedItemList
|
10
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
11
|
+
from .snrefcontext import SnRefContext
|
12
|
+
from .table import Table
|
13
|
+
|
14
|
+
|
15
|
+
@dataclass
|
16
|
+
class DynIdDefModeInfo:
|
17
|
+
def_mode: str
|
18
|
+
|
19
|
+
clear_dyn_def_message_ref: OdxLinkRef | None
|
20
|
+
clear_dyn_def_message_snref: str | None
|
21
|
+
|
22
|
+
read_dyn_def_message_ref: OdxLinkRef | None
|
23
|
+
read_dyn_def_message_snref: str | None
|
24
|
+
|
25
|
+
dyn_def_message_ref: OdxLinkRef | None
|
26
|
+
dyn_def_message_snref: str | None
|
27
|
+
|
28
|
+
supported_dyn_ids: list[bytes]
|
29
|
+
selection_table_refs: list[OdxLinkRef | str]
|
30
|
+
|
31
|
+
@property
|
32
|
+
def clear_dyn_def_message(self) -> DiagComm:
|
33
|
+
return self._clear_dyn_def_message
|
34
|
+
|
35
|
+
@property
|
36
|
+
def read_dyn_def_message(self) -> DiagComm:
|
37
|
+
return self._read_dyn_def_message
|
38
|
+
|
39
|
+
@property
|
40
|
+
def dyn_def_message(self) -> DiagComm:
|
41
|
+
return self._dyn_def_message
|
42
|
+
|
43
|
+
@property
|
44
|
+
def selection_tables(self) -> NamedItemList[Table]:
|
45
|
+
return self._selection_tables
|
46
|
+
|
47
|
+
@staticmethod
|
48
|
+
def from_et(et_element: ElementTree.Element,
|
49
|
+
doc_frags: list[OdxDocFragment]) -> "DynIdDefModeInfo":
|
50
|
+
def_mode = odxrequire(et_element.findtext("DEF-MODE"))
|
51
|
+
|
52
|
+
clear_dyn_def_message_ref = OdxLinkRef.from_et(
|
53
|
+
et_element.find("CLEAR-DYN-DEF-MESSAGE-REF"), doc_frags)
|
54
|
+
clear_dyn_def_message_snref = None
|
55
|
+
if (snref_elem := et_element.find("CLEAR-DYN-DEF-MESSAGE-SNREF")) is not None:
|
56
|
+
clear_dyn_def_message_snref = odxrequire(snref_elem.attrib.get("SHORT-NAME"))
|
57
|
+
|
58
|
+
read_dyn_def_message_ref = OdxLinkRef.from_et(
|
59
|
+
et_element.find("READ-DYN-DEF-MESSAGE-REF"), doc_frags)
|
60
|
+
read_dyn_def_message_snref = None
|
61
|
+
if (snref_elem := et_element.find("READ-DYN-DEF-MESSAGE-SNREF")) is not None:
|
62
|
+
read_dyn_def_message_snref = odxrequire(snref_elem.attrib.get("SHORT-NAME"))
|
63
|
+
|
64
|
+
dyn_def_message_ref = OdxLinkRef.from_et(et_element.find("DYN-DEF-MESSAGE-REF"), doc_frags)
|
65
|
+
dyn_def_message_snref = None
|
66
|
+
if (snref_elem := et_element.find("DYN-DEF-MESSAGE-SNREF")) is not None:
|
67
|
+
dyn_def_message_snref = odxrequire(snref_elem.attrib.get("SHORT-NAME"))
|
68
|
+
|
69
|
+
supported_dyn_ids = [
|
70
|
+
bytes.fromhex(odxrequire(x.text))
|
71
|
+
for x in et_element.iterfind("SUPPORTED-DYN-IDS/SUPPORTED-DYN-ID")
|
72
|
+
]
|
73
|
+
|
74
|
+
selection_table_refs: list[OdxLinkRef | str] = []
|
75
|
+
if (st_elems := et_element.find("SELECTION-TABLE-REFS")) is not None:
|
76
|
+
for st_elem in st_elems:
|
77
|
+
if st_elem.tag == "SELECTION-TABLE-REF":
|
78
|
+
selection_table_refs.append(OdxLinkRef.from_et(st_elem, doc_frags))
|
79
|
+
elif st_elem.tag == "SELECTION-TABLE-SNREF":
|
80
|
+
selection_table_refs.append(odxrequire(st_elem.get("SHORT-NAME")))
|
81
|
+
else:
|
82
|
+
odxraise()
|
83
|
+
|
84
|
+
return DynIdDefModeInfo(
|
85
|
+
def_mode=def_mode,
|
86
|
+
clear_dyn_def_message_ref=clear_dyn_def_message_ref,
|
87
|
+
clear_dyn_def_message_snref=clear_dyn_def_message_snref,
|
88
|
+
read_dyn_def_message_ref=read_dyn_def_message_ref,
|
89
|
+
read_dyn_def_message_snref=read_dyn_def_message_snref,
|
90
|
+
dyn_def_message_ref=dyn_def_message_ref,
|
91
|
+
dyn_def_message_snref=dyn_def_message_snref,
|
92
|
+
supported_dyn_ids=supported_dyn_ids,
|
93
|
+
selection_table_refs=selection_table_refs,
|
94
|
+
)
|
95
|
+
|
96
|
+
def __post_init__(self) -> None:
|
97
|
+
odxassert(
|
98
|
+
self.clear_dyn_def_message_ref is not None or
|
99
|
+
self.clear_dyn_def_message_snref is not None,
|
100
|
+
"A CLEAR-DYN-DEF-MESSAGE must be specified")
|
101
|
+
odxassert(
|
102
|
+
self.read_dyn_def_message_ref is not None or
|
103
|
+
self.read_dyn_def_message_snref is not None, "A READ-DYN-DEF-MESSAGE must be specified")
|
104
|
+
odxassert(self.dyn_def_message_ref is not None or self.dyn_def_message_snref is not None,
|
105
|
+
"A DYN-DEF-MESSAGE must be specified")
|
106
|
+
|
107
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
108
|
+
result: dict[OdxLinkId, Any] = {}
|
109
|
+
|
110
|
+
return result
|
111
|
+
|
112
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
113
|
+
if self.clear_dyn_def_message_ref is not None:
|
114
|
+
self._clear_dyn_def_message = odxlinks.resolve(self.clear_dyn_def_message_ref, DiagComm)
|
115
|
+
|
116
|
+
if self.read_dyn_def_message_ref is not None:
|
117
|
+
self._read_dyn_def_message = odxlinks.resolve(self.read_dyn_def_message_ref, DiagComm)
|
118
|
+
|
119
|
+
if self.dyn_def_message_ref is not None:
|
120
|
+
self._dyn_def_message = odxlinks.resolve(self.dyn_def_message_ref, DiagComm)
|
121
|
+
|
122
|
+
# resolve the selection tables that are referenced via ODXLINK
|
123
|
+
self._selection_tables = NamedItemList[Table]()
|
124
|
+
for x in self.selection_table_refs:
|
125
|
+
if isinstance(x, OdxLinkRef):
|
126
|
+
self._selection_tables.append(odxlinks.resolve(x, Table))
|
127
|
+
|
128
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
129
|
+
diag_layer = odxrequire(context.diag_layer)
|
130
|
+
|
131
|
+
if self.clear_dyn_def_message_snref is not None:
|
132
|
+
self._clear_dyn_def_message = resolve_snref(self.clear_dyn_def_message_snref,
|
133
|
+
diag_layer.diag_comms, DiagComm)
|
134
|
+
|
135
|
+
if self.read_dyn_def_message_snref is not None:
|
136
|
+
self._read_dyn_def_message = resolve_snref(self.read_dyn_def_message_snref,
|
137
|
+
diag_layer.diag_comms, DiagComm)
|
138
|
+
|
139
|
+
if self.dyn_def_message_snref is not None:
|
140
|
+
self._dyn_def_message = resolve_snref(self.dyn_def_message_snref, diag_layer.diag_comms,
|
141
|
+
DiagComm)
|
142
|
+
|
143
|
+
if self._clear_dyn_def_message.diagnostic_class != DiagClassType.CLEAR_DYN_DEF_MESSAGE:
|
144
|
+
odxraise(
|
145
|
+
f"Diagnostic communication object of wrong type referenced: "
|
146
|
+
f"({odxrequire(self._clear_dyn_def_message.diagnostic_class).value} instead of "
|
147
|
+
f"CLEAR-DYN-DEF-MESSAGE)")
|
148
|
+
if self._read_dyn_def_message.diagnostic_class != DiagClassType.READ_DYN_DEFINED_MESSAGE:
|
149
|
+
odxraise(f"Diagnostic communication object of wrong type referenced: "
|
150
|
+
f"({odxrequire(self._read_dyn_def_message.diagnostic_class).value} instead of "
|
151
|
+
f"READ-DYN-DEFINED-MESSAGE)")
|
152
|
+
if self._dyn_def_message.diagnostic_class != DiagClassType.DYN_DEF_MESSAGE:
|
153
|
+
odxraise(f"Diagnostic communication object of wrong type referenced: "
|
154
|
+
f"({odxrequire(self._dyn_def_message.diagnostic_class).value} instead of "
|
155
|
+
f"DYN-DEF-MESSAGE)")
|
156
|
+
|
157
|
+
# resolve the remaining selection tables that are referenced via SNREF
|
158
|
+
ddd_spec = odxrequire(diag_layer.diag_data_dictionary_spec)
|
159
|
+
for i, x in enumerate(self.selection_table_refs):
|
160
|
+
if isinstance(x, str):
|
161
|
+
self._selection_tables.insert(i, resolve_snref(x, ddd_spec.tables, Table))
|
odxtools/ecuvariantpattern.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import List, Union
|
4
3
|
from xml.etree import ElementTree
|
5
4
|
|
6
5
|
from typing_extensions import override
|
@@ -17,16 +16,16 @@ class EcuVariantPattern(VariantPattern):
|
|
17
16
|
"""ECU variant patterns are variant patterns used to identify the
|
18
17
|
concrete variant of an ECU.
|
19
18
|
"""
|
20
|
-
matching_parameters:
|
19
|
+
matching_parameters: list[MatchingParameter]
|
21
20
|
|
22
21
|
@override
|
23
|
-
def get_matching_parameters(
|
24
|
-
|
22
|
+
def get_matching_parameters(self
|
23
|
+
) -> list[MatchingParameter] | list[MatchingBaseVariantParameter]:
|
25
24
|
return self.matching_parameters
|
26
25
|
|
27
26
|
@staticmethod
|
28
27
|
def from_et(et_element: ElementTree.Element,
|
29
|
-
doc_frags:
|
28
|
+
doc_frags: list[OdxDocFragment]) -> "EcuVariantPattern":
|
30
29
|
|
31
30
|
matching_parameters = [
|
32
31
|
MatchingParameter.from_et(mp_el, doc_frags)
|
odxtools/element.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from typing import List, Optional
|
3
2
|
from xml.etree import ElementTree
|
4
3
|
|
5
4
|
from .description import Description
|
@@ -11,11 +10,11 @@ from .utils import dataclass_fields_asdict
|
|
11
10
|
@dataclass
|
12
11
|
class NamedElement:
|
13
12
|
short_name: str
|
14
|
-
long_name:
|
15
|
-
description:
|
13
|
+
long_name: str | None
|
14
|
+
description: Description | None
|
16
15
|
|
17
16
|
@staticmethod
|
18
|
-
def from_et(et_element: ElementTree.Element, doc_frags:
|
17
|
+
def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "NamedElement":
|
19
18
|
|
20
19
|
return NamedElement(
|
21
20
|
short_name=odxrequire(et_element.findtext("SHORT-NAME")),
|
@@ -27,11 +26,11 @@ class NamedElement:
|
|
27
26
|
@dataclass
|
28
27
|
class IdentifiableElement(NamedElement):
|
29
28
|
odx_id: OdxLinkId
|
30
|
-
oid:
|
29
|
+
oid: str | None
|
31
30
|
|
32
31
|
@staticmethod
|
33
32
|
def from_et(et_element: ElementTree.Element,
|
34
|
-
doc_frags:
|
33
|
+
doc_frags: list[OdxDocFragment]) -> "IdentifiableElement":
|
35
34
|
|
36
35
|
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
|
37
36
|
|
odxtools/encodestate.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
import warnings
|
3
3
|
from dataclasses import dataclass, field
|
4
|
-
from typing import TYPE_CHECKING
|
4
|
+
from typing import TYPE_CHECKING
|
5
5
|
|
6
6
|
from .encoding import Encoding, get_string_encoding
|
7
7
|
from .exceptions import EncodeError, OdxWarning, odxassert, odxraise
|
@@ -41,20 +41,20 @@ class EncodeState:
|
|
41
41
|
cursor_bit_position: int = 0
|
42
42
|
|
43
43
|
#: If encoding a response: request that triggered the response
|
44
|
-
triggering_request:
|
44
|
+
triggering_request: bytes | None = None
|
45
45
|
|
46
46
|
#: Mapping from the short name of a length-key parameter to bit
|
47
47
|
#: lengths (specified by LengthKeyParameter)
|
48
|
-
length_keys:
|
48
|
+
length_keys: dict[str, int] = field(default_factory=dict)
|
49
49
|
|
50
50
|
#: Mapping from the short name of a table-key parameter to the
|
51
51
|
#: short name of the corresponding row of the table (specified by
|
52
52
|
#: TableKeyParameter)
|
53
|
-
table_keys:
|
53
|
+
table_keys: dict[str, str] = field(default_factory=dict)
|
54
54
|
|
55
55
|
#: The cursor position where a given length- or table key is located
|
56
56
|
#: in the PDU
|
57
|
-
key_pos:
|
57
|
+
key_pos: dict[str, int] = field(default_factory=dict)
|
58
58
|
|
59
59
|
#: Flag whether we are currently the last parameter of the PDU
|
60
60
|
#: (needed for MinMaxLengthType, EndOfPduField, etc.)
|
@@ -63,7 +63,7 @@ class EncodeState:
|
|
63
63
|
#: list of parameters that have been encoded so far. The journal
|
64
64
|
#: is used by some types of parameters which depend on the values of
|
65
65
|
#: other parameters; e.g., environment data description parameters
|
66
|
-
journal:
|
66
|
+
journal: list[tuple["Parameter", ParameterValue | None]] = field(default_factory=list)
|
67
67
|
|
68
68
|
#: If this is True, specifying unknown parameters for encoding
|
69
69
|
#: will raise an OdxError exception in strict mode.
|
@@ -87,9 +87,9 @@ class EncodeState:
|
|
87
87
|
internal_value: AtomicOdxType,
|
88
88
|
bit_length: int,
|
89
89
|
base_data_type: DataType,
|
90
|
-
base_type_encoding:
|
90
|
+
base_type_encoding: Encoding | None,
|
91
91
|
is_highlow_byte_order: bool,
|
92
|
-
used_mask:
|
92
|
+
used_mask: bytes | None,
|
93
93
|
) -> None:
|
94
94
|
"""Convert the internal_value to bytes and emplace this into the PDU"""
|
95
95
|
|
@@ -220,7 +220,7 @@ class EncodeState:
|
|
220
220
|
odxraise(f"Illegal bit length for a float64 object ({bit_length})")
|
221
221
|
bit_length = 64
|
222
222
|
|
223
|
-
raw_value = float(internal_value)
|
223
|
+
raw_value = float(internal_value) # type: ignore[arg-type]
|
224
224
|
|
225
225
|
# If the bit length is zero, encode an empty value
|
226
226
|
if bit_length == 0:
|
@@ -260,8 +260,8 @@ class EncodeState:
|
|
260
260
|
|
261
261
|
def emplace_bytes(self,
|
262
262
|
new_data: bytes,
|
263
|
-
obj_name:
|
264
|
-
obj_used_mask:
|
263
|
+
obj_name: str | None = None,
|
264
|
+
obj_used_mask: bytes | None = None) -> None:
|
265
265
|
if self.cursor_bit_position != 0:
|
266
266
|
odxraise("EncodeState.emplace_bytes can only be called "
|
267
267
|
"for a bit position of 0!", RuntimeError)
|
odxtools/encoding.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from enum import Enum
|
3
|
-
from typing import Optional
|
4
3
|
|
5
4
|
from .exceptions import odxraise
|
6
5
|
from .odxtypes import DataType
|
@@ -23,8 +22,8 @@ class Encoding(Enum):
|
|
23
22
|
NONE = "NONE"
|
24
23
|
|
25
24
|
|
26
|
-
def get_string_encoding(base_data_type: DataType, base_type_encoding:
|
27
|
-
is_highlow_byte_order: bool) ->
|
25
|
+
def get_string_encoding(base_data_type: DataType, base_type_encoding: Encoding | None,
|
26
|
+
is_highlow_byte_order: bool) -> str | None:
|
28
27
|
"""If the encoding is for a string, return the value for
|
29
28
|
`str.encode()`/`str.decode()` to convert the string object
|
30
29
|
to/from a byte array
|
odxtools/endofpdufield.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
+
from collections.abc import Sequence
|
2
3
|
from dataclasses import dataclass
|
3
|
-
from typing import List, Optional, Sequence
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from typing_extensions import override
|
@@ -17,12 +17,12 @@ from .utils import dataclass_fields_asdict
|
|
17
17
|
@dataclass
|
18
18
|
class EndOfPduField(Field):
|
19
19
|
"""End of PDU fields are structures that are repeated until the end of the PDU"""
|
20
|
-
max_number_of_items:
|
21
|
-
min_number_of_items:
|
20
|
+
max_number_of_items: int | None
|
21
|
+
min_number_of_items: int | None
|
22
22
|
|
23
23
|
@staticmethod
|
24
24
|
def from_et(et_element: ElementTree.Element,
|
25
|
-
doc_frags:
|
25
|
+
doc_frags: list[OdxDocFragment]) -> "EndOfPduField":
|
26
26
|
kwargs = dataclass_fields_asdict(Field.from_et(et_element, doc_frags))
|
27
27
|
|
28
28
|
if (max_n_str := et_element.findtext("MAX-NUMBER-OF-ITEMS")) is not None:
|
@@ -40,7 +40,7 @@ class EndOfPduField(Field):
|
|
40
40
|
**kwargs)
|
41
41
|
|
42
42
|
@override
|
43
|
-
def encode_into_pdu(self, physical_value:
|
43
|
+
def encode_into_pdu(self, physical_value: ParameterValue | None,
|
44
44
|
encode_state: EncodeState) -> None:
|
45
45
|
odxassert(not encode_state.cursor_bit_position,
|
46
46
|
"No bit position can be specified for end-of-pdu fields!")
|
@@ -72,7 +72,7 @@ class EndOfPduField(Field):
|
|
72
72
|
orig_origin = decode_state.origin_byte_position
|
73
73
|
decode_state.origin_byte_position = decode_state.cursor_byte_position
|
74
74
|
|
75
|
-
result:
|
75
|
+
result: list[ParameterValue] = []
|
76
76
|
while decode_state.cursor_byte_position < len(decode_state.coded_message):
|
77
77
|
# ATTENTION: the ODX specification is very misleading
|
78
78
|
# here: it says that the item is repeated until the end of
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Any
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from .element import NamedElement
|
7
|
+
from .environmentdata import EnvironmentData
|
8
|
+
from .environmentdatadescription import EnvironmentDataDescription
|
9
|
+
from .exceptions import odxrequire
|
10
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
11
|
+
from .snrefcontext import SnRefContext
|
12
|
+
from .utils import dataclass_fields_asdict
|
13
|
+
|
14
|
+
|
15
|
+
@dataclass
|
16
|
+
class EnvDataConnector(NamedElement):
|
17
|
+
env_data_desc_ref: OdxLinkRef
|
18
|
+
env_data_snref: str
|
19
|
+
|
20
|
+
@property
|
21
|
+
def env_data_desc(self) -> EnvironmentDataDescription:
|
22
|
+
return self._env_data_desc
|
23
|
+
|
24
|
+
@property
|
25
|
+
def env_data(self) -> EnvironmentData:
|
26
|
+
return self._env_data
|
27
|
+
|
28
|
+
@staticmethod
|
29
|
+
def from_et(et_element: ElementTree.Element,
|
30
|
+
doc_frags: list[OdxDocFragment]) -> "EnvDataConnector":
|
31
|
+
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
|
32
|
+
|
33
|
+
env_data_desc_ref = odxrequire(
|
34
|
+
OdxLinkRef.from_et(et_element.find("ENV-DATA-DESC-REF"), doc_frags))
|
35
|
+
env_data_snref_el = odxrequire(et_element.find("ENV-DATA-SNREF"))
|
36
|
+
env_data_snref = odxrequire(env_data_snref_el.get("SHORT-NAME"))
|
37
|
+
|
38
|
+
return EnvDataConnector(
|
39
|
+
env_data_desc_ref=env_data_desc_ref, env_data_snref=env_data_snref, **kwargs)
|
40
|
+
|
41
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
42
|
+
return {}
|
43
|
+
|
44
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
45
|
+
self._env_data_desc = odxlinks.resolve(self.env_data_desc_ref, EnvironmentDataDescription)
|
46
|
+
|
47
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
48
|
+
self._env_data = resolve_snref(self.env_data_snref, self._env_data_desc.env_datas,
|
49
|
+
EnvironmentData)
|
odxtools/environmentdata.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import List, Optional
|
4
3
|
from xml.etree import ElementTree
|
5
4
|
|
6
5
|
from .basicstructure import BasicStructure
|
@@ -20,12 +19,12 @@ class EnvironmentData(BasicStructure):
|
|
20
19
|
sense, it is quite similar to NRC-CONST parameters.)
|
21
20
|
"""
|
22
21
|
|
23
|
-
all_value:
|
24
|
-
dtc_values:
|
22
|
+
all_value: bool | None
|
23
|
+
dtc_values: list[int]
|
25
24
|
|
26
25
|
@staticmethod
|
27
26
|
def from_et(et_element: ElementTree.Element,
|
28
|
-
doc_frags:
|
27
|
+
doc_frags: list[OdxDocFragment]) -> "EnvironmentData":
|
29
28
|
"""Reads Environment Data from Diag Layer."""
|
30
29
|
kwargs = dataclass_fields_asdict(BasicStructure.from_et(et_element, doc_frags))
|
31
30
|
|
@@ -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 typing_extensions import override
|
@@ -35,18 +35,18 @@ class EnvironmentDataDescription(ComplexDop):
|
|
35
35
|
|
36
36
|
"""
|
37
37
|
|
38
|
-
param_snref:
|
39
|
-
param_snpathref:
|
38
|
+
param_snref: str | None
|
39
|
+
param_snpathref: str | None
|
40
40
|
|
41
41
|
# in ODX 2.0.0, ENV-DATAS seems to be a mandatory
|
42
42
|
# sub-element of ENV-DATA-DESC, in ODX 2.2 it is not
|
43
43
|
# present
|
44
44
|
env_datas: NamedItemList[EnvironmentData]
|
45
|
-
env_data_refs:
|
45
|
+
env_data_refs: list[OdxLinkRef]
|
46
46
|
|
47
47
|
@staticmethod
|
48
48
|
def from_et(et_element: ElementTree.Element,
|
49
|
-
doc_frags:
|
49
|
+
doc_frags: list[OdxDocFragment]) -> "EnvironmentDataDescription":
|
50
50
|
"""Reads Environment Data Description from Diag Layer."""
|
51
51
|
kwargs = dataclass_fields_asdict(ComplexDop.from_et(et_element, doc_frags))
|
52
52
|
|
@@ -78,7 +78,7 @@ class EnvironmentDataDescription(ComplexDop):
|
|
78
78
|
env_data_refs=env_data_refs,
|
79
79
|
**kwargs)
|
80
80
|
|
81
|
-
def _build_odxlinks(self) ->
|
81
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
82
82
|
odxlinks = {self.odx_id: self}
|
83
83
|
|
84
84
|
if not self.env_data_refs:
|
@@ -105,7 +105,7 @@ class EnvironmentDataDescription(ComplexDop):
|
|
105
105
|
ed._resolve_snrefs(context)
|
106
106
|
|
107
107
|
@override
|
108
|
-
def encode_into_pdu(self, physical_value:
|
108
|
+
def encode_into_pdu(self, physical_value: ParameterValue | None,
|
109
109
|
encode_state: EncodeState) -> None:
|
110
110
|
"""Convert a physical value into bytes and emplace them into a PDU.
|
111
111
|
"""
|
@@ -118,7 +118,7 @@ class EnvironmentDataDescription(ComplexDop):
|
|
118
118
|
"descriptions via SNPATHREF is not supported yet")
|
119
119
|
return None
|
120
120
|
|
121
|
-
numerical_dtc_value:
|
121
|
+
numerical_dtc_value: ParameterValue | None = None
|
122
122
|
for prev_param, prev_param_value in reversed(encode_state.journal):
|
123
123
|
if prev_param.short_name == self.param_snref:
|
124
124
|
numerical_dtc_value = self._get_numerical_dtc_from_parameter(
|
@@ -165,7 +165,7 @@ class EnvironmentDataDescription(ComplexDop):
|
|
165
165
|
"descriptions via SNPATHREF is not supported yet")
|
166
166
|
return None
|
167
167
|
|
168
|
-
numerical_dtc_value:
|
168
|
+
numerical_dtc_value: ParameterValue | None = None
|
169
169
|
for prev_param, prev_param_value in reversed(decode_state.journal):
|
170
170
|
if prev_param.short_name == self.param_snref:
|
171
171
|
numerical_dtc_value = self._get_numerical_dtc_from_parameter(
|
@@ -204,10 +204,10 @@ class EnvironmentDataDescription(ComplexDop):
|
|
204
204
|
return result
|
205
205
|
|
206
206
|
def _get_numerical_dtc_from_parameter(self, param: Parameter,
|
207
|
-
param_value:
|
207
|
+
param_value: ParameterValue | None) -> int:
|
208
208
|
if isinstance(param, ParameterWithDOP):
|
209
209
|
dop = param.dop
|
210
|
-
if not isinstance(dop,
|
210
|
+
if not isinstance(dop, DataObjectProperty | DtcDop):
|
211
211
|
odxraise(f"The DOP of the parameter referenced by environment data descriptions "
|
212
212
|
f"must use either be DataObjectProperty or a DtcDop (encountered "
|
213
213
|
f"{type(param).__name__} for parameter '{param.short_name}' "
|
odxtools/exceptions.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
-
from typing import TYPE_CHECKING, NoReturn,
|
2
|
+
from typing import TYPE_CHECKING, NoReturn, TypeVar
|
3
3
|
|
4
4
|
from .globals import logger
|
5
5
|
|
@@ -37,7 +37,7 @@ class OdxWarning(Warning):
|
|
37
37
|
strict_mode = True
|
38
38
|
|
39
39
|
|
40
|
-
def odxraise(message:
|
40
|
+
def odxraise(message: str | None = None, error_type: type[Exception] = OdxError) -> NoReturn:
|
41
41
|
"""
|
42
42
|
Raise an exception but only if in strict mode.
|
43
43
|
|
@@ -53,8 +53,8 @@ def odxraise(message: Optional[str] = None, error_type: Type[Exception] = OdxErr
|
|
53
53
|
|
54
54
|
|
55
55
|
def odxassert(condition: bool,
|
56
|
-
message:
|
57
|
-
error_type:
|
56
|
+
message: str | None = None,
|
57
|
+
error_type: type[Exception] = OdxError) -> None:
|
58
58
|
"""
|
59
59
|
This method works similar as the build-in `assert` statement
|
60
60
|
|
@@ -72,7 +72,7 @@ def odxassert(condition: bool,
|
|
72
72
|
T = TypeVar("T")
|
73
73
|
|
74
74
|
|
75
|
-
def odxrequire(obj:
|
75
|
+
def odxrequire(obj: T | None, message: str | None = None) -> T:
|
76
76
|
"""This function ensures that an object required by the ODX
|
77
77
|
specification is actually present.
|
78
78
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from xml.etree import ElementTree
|
4
|
+
|
5
|
+
from .element import IdentifiableElement
|
6
|
+
from .exceptions import odxrequire
|
7
|
+
from .odxlink import OdxDocFragment
|
8
|
+
from .utils import dataclass_fields_asdict
|
9
|
+
|
10
|
+
|
11
|
+
@dataclass
|
12
|
+
class ExternalAccessMethod(IdentifiableElement):
|
13
|
+
method: str
|
14
|
+
|
15
|
+
@staticmethod
|
16
|
+
def from_et(et_element: ElementTree.Element,
|
17
|
+
doc_frags: list[OdxDocFragment]) -> "ExternalAccessMethod":
|
18
|
+
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
19
|
+
|
20
|
+
method = odxrequire(et_element.findtext("METHOD"))
|
21
|
+
|
22
|
+
return ExternalAccessMethod(method=method, **kwargs)
|
odxtools/externaldoc.py
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import Optional
|
3
|
+
from xml.etree import ElementTree
|
4
|
+
|
5
|
+
from .exceptions import odxrequire
|
6
|
+
from .odxlink import OdxDocFragment
|
7
|
+
|
8
|
+
|
9
|
+
@dataclass
|
10
|
+
class ExternalDoc:
|
11
|
+
description: str | None
|
12
|
+
href: str
|
13
|
+
|
14
|
+
@staticmethod
|
15
|
+
def from_et(et_element: ElementTree.Element | None,
|
16
|
+
doc_frags: list[OdxDocFragment]) -> Optional["ExternalDoc"]:
|
17
|
+
if et_element is None:
|
18
|
+
return None
|
19
|
+
|
20
|
+
description = et_element.text
|
21
|
+
href = odxrequire(et_element.get("HREF"))
|
22
|
+
|
23
|
+
return ExternalDoc(description=description, href=href)
|
odxtools/field.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import List, Optional
|
4
3
|
from xml.etree import ElementTree
|
5
4
|
|
6
5
|
from .basicstructure import BasicStructure
|
@@ -15,11 +14,11 @@ from .utils import dataclass_fields_asdict
|
|
15
14
|
|
16
15
|
@dataclass
|
17
16
|
class Field(ComplexDop):
|
18
|
-
structure_ref:
|
19
|
-
structure_snref:
|
20
|
-
env_data_desc_ref:
|
21
|
-
env_data_desc_snref:
|
22
|
-
is_visible_raw:
|
17
|
+
structure_ref: OdxLinkRef | None
|
18
|
+
structure_snref: str | None
|
19
|
+
env_data_desc_ref: OdxLinkRef | None
|
20
|
+
env_data_desc_snref: str | None
|
21
|
+
is_visible_raw: bool | None
|
23
22
|
|
24
23
|
@property
|
25
24
|
def structure(self) -> BasicStructure:
|
@@ -31,7 +30,7 @@ class Field(ComplexDop):
|
|
31
30
|
return self.is_visible_raw in (None, True)
|
32
31
|
|
33
32
|
@staticmethod
|
34
|
-
def from_et(et_element: ElementTree.Element, doc_frags:
|
33
|
+
def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "Field":
|
35
34
|
kwargs = dataclass_fields_asdict(ComplexDop.from_et(et_element, doc_frags))
|
36
35
|
|
37
36
|
structure_ref = OdxLinkRef.from_et(et_element.find("BASIC-STRUCTURE-REF"), doc_frags)
|
@@ -54,8 +53,8 @@ class Field(ComplexDop):
|
|
54
53
|
**kwargs)
|
55
54
|
|
56
55
|
def __post_init__(self) -> None:
|
57
|
-
self._structure:
|
58
|
-
self._env_data_desc:
|
56
|
+
self._structure: BasicStructure | None = None
|
57
|
+
self._env_data_desc: EnvironmentDataDescription | None = None
|
59
58
|
num_struct_refs = 0 if self.structure_ref is None else 1
|
60
59
|
num_struct_refs += 0 if self.structure_snref is None else 1
|
61
60
|
|
@@ -87,5 +86,5 @@ class Field(ComplexDop):
|
|
87
86
|
self._env_data_desc = resolve_snref(self.env_data_desc_snref, ddds.env_data_descs,
|
88
87
|
EnvironmentDataDescription)
|
89
88
|
|
90
|
-
def get_static_bit_length(self) ->
|
89
|
+
def get_static_bit_length(self) -> int | None:
|
91
90
|
return None
|