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
odxtools/functionalclass.py
CHANGED
@@ -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 .admindata import AdminData
|
@@ -16,11 +16,11 @@ class FunctionalClass(IdentifiableElement):
|
|
16
16
|
Corresponds to FUNCT-CLASS.
|
17
17
|
"""
|
18
18
|
|
19
|
-
admin_data:
|
19
|
+
admin_data: AdminData | None
|
20
20
|
|
21
21
|
@staticmethod
|
22
22
|
def from_et(et_element: ElementTree.Element,
|
23
|
-
doc_frags:
|
23
|
+
doc_frags: list[OdxDocFragment]) -> "FunctionalClass":
|
24
24
|
|
25
25
|
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
26
26
|
|
@@ -28,7 +28,7 @@ class FunctionalClass(IdentifiableElement):
|
|
28
28
|
|
29
29
|
return FunctionalClass(admin_data=admin_data, **kwargs)
|
30
30
|
|
31
|
-
def _build_odxlinks(self) ->
|
31
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
32
32
|
return {self.odx_id: self}
|
33
33
|
|
34
34
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
odxtools/inputparam.py
CHANGED
@@ -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 deprecation import deprecated
|
@@ -15,10 +15,10 @@ from .utils import dataclass_fields_asdict
|
|
15
15
|
|
16
16
|
@dataclass
|
17
17
|
class InputParam(NamedElement):
|
18
|
-
physical_default_value:
|
18
|
+
physical_default_value: str | None
|
19
19
|
dop_base_ref: OdxLinkRef
|
20
|
-
oid:
|
21
|
-
semantic:
|
20
|
+
oid: str | None
|
21
|
+
semantic: str | None
|
22
22
|
|
23
23
|
@property
|
24
24
|
def dop(self) -> DopBase:
|
@@ -30,7 +30,7 @@ class InputParam(NamedElement):
|
|
30
30
|
return self._dop
|
31
31
|
|
32
32
|
@staticmethod
|
33
|
-
def from_et(et_element: ElementTree.Element, doc_frags:
|
33
|
+
def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "InputParam":
|
34
34
|
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
|
35
35
|
|
36
36
|
physical_default_value = et_element.findtext("PHYSICAL-DEFAULT-VALUE")
|
@@ -46,7 +46,7 @@ class InputParam(NamedElement):
|
|
46
46
|
semantic=semantic,
|
47
47
|
**kwargs)
|
48
48
|
|
49
|
-
def _build_odxlinks(self) ->
|
49
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
50
50
|
return {}
|
51
51
|
|
52
52
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
odxtools/internalconstr.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 .compumethods.limit import Limit
|
@@ -16,14 +15,14 @@ class InternalConstr:
|
|
16
15
|
|
17
16
|
# TODO: Enforce the internal and physical constraints.
|
18
17
|
|
19
|
-
lower_limit:
|
20
|
-
upper_limit:
|
21
|
-
scale_constrs:
|
18
|
+
lower_limit: Limit | None
|
19
|
+
upper_limit: Limit | None
|
20
|
+
scale_constrs: list[ScaleConstr]
|
22
21
|
|
23
22
|
value_type: DataType
|
24
23
|
|
25
24
|
@staticmethod
|
26
|
-
def constr_from_et(et_element: ElementTree.Element, doc_frags:
|
25
|
+
def constr_from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment], *,
|
27
26
|
value_type: DataType) -> "InternalConstr":
|
28
27
|
|
29
28
|
lower_limit = Limit.limit_from_et(
|
odxtools/isotp_state_machine.py
CHANGED
@@ -4,9 +4,10 @@
|
|
4
4
|
import asyncio
|
5
5
|
import re
|
6
6
|
import sys
|
7
|
+
from collections.abc import AsyncGenerator, Iterable
|
7
8
|
from enum import IntEnum
|
8
9
|
from io import TextIOBase
|
9
|
-
from typing import
|
10
|
+
from typing import TextIO
|
10
11
|
|
11
12
|
import bitstruct
|
12
13
|
import can
|
@@ -32,7 +33,7 @@ class IsoTpStateMachine:
|
|
32
33
|
can_fd_log_frame_re = re.compile(
|
33
34
|
"\\([0-9.]*\\) *([a-zA-Z0-9_-]*) ([0-9A-Fa-f]+)##[0-9A-Fa-f]([0-9A-Fa-f]+)")
|
34
35
|
|
35
|
-
def __init__(self, can_rx_ids:
|
36
|
+
def __init__(self, can_rx_ids: int | list[int]):
|
36
37
|
if isinstance(can_rx_ids, int):
|
37
38
|
can_rx_ids = [can_rx_ids]
|
38
39
|
|
@@ -40,10 +41,10 @@ class IsoTpStateMachine:
|
|
40
41
|
assert isinstance(self._can_rx_ids, list)
|
41
42
|
|
42
43
|
self._telegram_specified_len = [0] * len(can_rx_ids)
|
43
|
-
self._telegram_data:
|
44
|
+
self._telegram_data: list[bytearray | None] = [None] * len(can_rx_ids)
|
44
45
|
self._telegram_last_rx_fragment_idx = [0] * len(can_rx_ids)
|
45
46
|
|
46
|
-
def decode_rx_frame(self, rx_id: int, data: bytes) -> Iterable[
|
47
|
+
def decode_rx_frame(self, rx_id: int, data: bytes) -> Iterable[tuple[int, bytes]]:
|
47
48
|
"""Handle the ISO-TP state transitions caused by a CAN frame.
|
48
49
|
|
49
50
|
E.g., add some data to a telegram, etc. Returns a generator of
|
@@ -114,8 +115,8 @@ class IsoTpStateMachine:
|
|
114
115
|
else:
|
115
116
|
self.on_frame_type_error(telegram_idx, frame_type)
|
116
117
|
|
117
|
-
async def read_telegrams(self,
|
118
|
-
|
118
|
+
async def read_telegrams(self,
|
119
|
+
bus: can.BusABC | TextIO) -> AsyncGenerator[tuple[int, bytes], None]:
|
119
120
|
"""This is equivalent to the :py:meth:`file.readlines()` method, but
|
120
121
|
it yields ISO-TP telegrams instead of lines.
|
121
122
|
|
@@ -184,7 +185,7 @@ class IsoTpStateMachine:
|
|
184
185
|
"""
|
185
186
|
return self._can_rx_ids[telegram_idx]
|
186
187
|
|
187
|
-
def telegram_data(self, telegram_idx: int) ->
|
188
|
+
def telegram_data(self, telegram_idx: int) -> bytes | None:
|
188
189
|
"""Given a Telegram index, returns the data received for this telegram
|
189
190
|
so far.
|
190
191
|
|
@@ -233,8 +234,8 @@ class IsoTpActiveDecoder(IsoTpStateMachine):
|
|
233
234
|
|
234
235
|
def __init__(self,
|
235
236
|
can_bus: can.BusABC,
|
236
|
-
can_rx_ids:
|
237
|
-
can_tx_ids:
|
237
|
+
can_rx_ids: list[int],
|
238
|
+
can_tx_ids: list[int],
|
238
239
|
padding_size: int = 0,
|
239
240
|
padding_value: int = 0xAA):
|
240
241
|
self._can_bus = can_bus
|
@@ -251,8 +252,8 @@ class IsoTpActiveDecoder(IsoTpStateMachine):
|
|
251
252
|
assert len(self._can_rx_ids) == len(self._can_tx_ids)
|
252
253
|
assert set(self._can_rx_ids).isdisjoint(set(self._can_tx_ids)) # correct?
|
253
254
|
|
254
|
-
self._block_size:
|
255
|
-
self._frames_received:
|
255
|
+
self._block_size: list[int | None] = [None] * len(self._can_rx_ids)
|
256
|
+
self._frames_received: list[int | None] = [None] * len(self._can_rx_ids)
|
256
257
|
|
257
258
|
def can_tx_id(self, telegram_idx: int) -> int:
|
258
259
|
"""Given a Telegram index, returns the CAN ID for sending data.
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import List
|
4
3
|
from xml.etree import ElementTree
|
5
4
|
|
6
5
|
from typing_extensions import override
|
@@ -30,7 +29,7 @@ class LeadingLengthInfoType(DiagCodedType):
|
|
30
29
|
@staticmethod
|
31
30
|
@override
|
32
31
|
def from_et(et_element: ElementTree.Element,
|
33
|
-
doc_frags:
|
32
|
+
doc_frags: list[OdxDocFragment]) -> "LeadingLengthInfoType":
|
34
33
|
kwargs = dataclass_fields_asdict(DiagCodedType.from_et(et_element, doc_frags))
|
35
34
|
|
36
35
|
bit_length = int(odxrequire(et_element.findtext("BIT-LENGTH")))
|
@@ -53,7 +52,7 @@ class LeadingLengthInfoType(DiagCodedType):
|
|
53
52
|
@override
|
54
53
|
def encode_into_pdu(self, internal_value: AtomicOdxType, encode_state: EncodeState) -> None:
|
55
54
|
|
56
|
-
if not isinstance(internal_value,
|
55
|
+
if not isinstance(internal_value, str | bytes):
|
57
56
|
odxraise(
|
58
57
|
f"LEADING-LENGTH-INFO types can only be used for strings and byte fields, "
|
59
58
|
f"not {type(internal_value).__name__}", EncodeError)
|
odxtools/library.py
CHANGED
@@ -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, cast
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .element import IdentifiableElement
|
@@ -19,17 +19,17 @@ class Library(IdentifiableElement):
|
|
19
19
|
"""
|
20
20
|
|
21
21
|
code_file: str
|
22
|
-
encryption:
|
22
|
+
encryption: str | None
|
23
23
|
syntax: str
|
24
24
|
revision: str
|
25
|
-
entrypoint:
|
25
|
+
entrypoint: str | None
|
26
26
|
|
27
27
|
@property
|
28
28
|
def code(self) -> bytes:
|
29
29
|
return self._code
|
30
30
|
|
31
31
|
@staticmethod
|
32
|
-
def from_et(et_element: ElementTree.Element, doc_frags:
|
32
|
+
def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "Library":
|
33
33
|
|
34
34
|
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
35
35
|
|
@@ -47,7 +47,7 @@ class Library(IdentifiableElement):
|
|
47
47
|
entrypoint=entrypoint,
|
48
48
|
**kwargs)
|
49
49
|
|
50
|
-
def _build_odxlinks(self) ->
|
50
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
51
51
|
return {self.odx_id: self}
|
52
52
|
|
53
53
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
odxtools/linkeddtcdop.py
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import TYPE_CHECKING, Any
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from .diagnostictroublecode import DiagnosticTroubleCode
|
7
|
+
from .exceptions import odxrequire
|
8
|
+
from .nameditemlist import NamedItemList
|
9
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
10
|
+
from .snrefcontext import SnRefContext
|
11
|
+
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from .dtcdop import DtcDop
|
14
|
+
|
15
|
+
|
16
|
+
@dataclass
|
17
|
+
class LinkedDtcDop:
|
18
|
+
not_inherited_dtc_snrefs: list[str]
|
19
|
+
dtc_dop_ref: OdxLinkRef
|
20
|
+
|
21
|
+
@property
|
22
|
+
def not_inherited_dtcs(self) -> NamedItemList[DiagnosticTroubleCode]:
|
23
|
+
return self._not_inherited_dtcs
|
24
|
+
|
25
|
+
@property
|
26
|
+
def dtc_dop(self) -> "DtcDop":
|
27
|
+
return self._dtc_dop
|
28
|
+
|
29
|
+
@property
|
30
|
+
def short_name(self) -> str:
|
31
|
+
return self._dtc_dop.short_name
|
32
|
+
|
33
|
+
@staticmethod
|
34
|
+
def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "LinkedDtcDop":
|
35
|
+
not_inherited_dtc_snrefs = [
|
36
|
+
odxrequire(el.get("SHORT-NAME"))
|
37
|
+
for el in et_element.iterfind("NOT-INHERITED-DTC-SNREFS/"
|
38
|
+
"NOT-INHERITED-DTC-SNREF")
|
39
|
+
]
|
40
|
+
|
41
|
+
dtc_dop_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DTC-DOP-REF"), doc_frags))
|
42
|
+
|
43
|
+
return LinkedDtcDop(
|
44
|
+
not_inherited_dtc_snrefs=not_inherited_dtc_snrefs, dtc_dop_ref=dtc_dop_ref)
|
45
|
+
|
46
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
47
|
+
return {}
|
48
|
+
|
49
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
50
|
+
if TYPE_CHECKING:
|
51
|
+
self._dtc_dop = odxlinks.resolve(self.dtc_dop_ref, DtcDop)
|
52
|
+
else:
|
53
|
+
self._dtc_dop = odxlinks.resolve(self.dtc_dop_ref)
|
54
|
+
|
55
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
56
|
+
dtc_dop = self._dtc_dop
|
57
|
+
not_inherited_dtcs = [
|
58
|
+
resolve_snref(ni_snref, dtc_dop.dtcs, DiagnosticTroubleCode)
|
59
|
+
for ni_snref in self.not_inherited_dtc_snrefs
|
60
|
+
]
|
61
|
+
|
62
|
+
self._not_inherited_dtcs = NamedItemList(not_inherited_dtcs)
|
odxtools/loadfile.py
CHANGED
@@ -1,19 +1,18 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
import os
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import Union
|
5
4
|
|
6
5
|
from .database import Database
|
7
6
|
|
8
7
|
|
9
|
-
def load_pdx_file(pdx_file:
|
8
|
+
def load_pdx_file(pdx_file: str | Path) -> Database:
|
10
9
|
db = Database()
|
11
10
|
db.add_pdx_file(str(pdx_file))
|
12
11
|
db.refresh()
|
13
12
|
return db
|
14
13
|
|
15
14
|
|
16
|
-
def load_odx_d_file(odx_d_file_name:
|
15
|
+
def load_odx_d_file(odx_d_file_name: str | Path) -> Database:
|
17
16
|
db = Database()
|
18
17
|
db.add_odx_file(str(odx_d_file_name))
|
19
18
|
db.refresh()
|
@@ -21,7 +20,7 @@ def load_odx_d_file(odx_d_file_name: Union[str, Path]) -> Database:
|
|
21
20
|
return db
|
22
21
|
|
23
22
|
|
24
|
-
def load_file(file_name:
|
23
|
+
def load_file(file_name: str | Path) -> Database:
|
25
24
|
if str(file_name).lower().endswith(".pdx"):
|
26
25
|
return load_pdx_file(str(file_name))
|
27
26
|
elif str(file_name).lower().endswith(".odx-d"):
|
@@ -30,7 +29,7 @@ def load_file(file_name: Union[str, Path]) -> Database:
|
|
30
29
|
raise RuntimeError(f"Could not guess the file format of file '{file_name}'!")
|
31
30
|
|
32
31
|
|
33
|
-
def load_files(*file_names:
|
32
|
+
def load_files(*file_names: str | Path) -> Database:
|
34
33
|
db = Database()
|
35
34
|
for file_name in file_names:
|
36
35
|
p = Path(file_name)
|
@@ -45,7 +44,7 @@ def load_files(*file_names: Union[str, Path]) -> Database:
|
|
45
44
|
return db
|
46
45
|
|
47
46
|
|
48
|
-
def load_directory(dir_name:
|
47
|
+
def load_directory(dir_name: str | Path) -> Database:
|
49
48
|
db = Database()
|
50
49
|
for file_name in os.listdir(str(dir_name)):
|
51
50
|
p = Path(dir_name) / file_name
|
@@ -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 .matchingparameter import MatchingParameter
|
@@ -18,7 +17,7 @@ class MatchingBaseVariantParameter(MatchingParameter):
|
|
18
17
|
additional subtag `USE-PHYSICAL-ADDRESSING`.
|
19
18
|
"""
|
20
19
|
|
21
|
-
use_physical_addressing_raw:
|
20
|
+
use_physical_addressing_raw: bool | None
|
22
21
|
|
23
22
|
@property
|
24
23
|
def use_physical_addressing(self) -> bool:
|
@@ -26,7 +25,7 @@ class MatchingBaseVariantParameter(MatchingParameter):
|
|
26
25
|
|
27
26
|
@staticmethod
|
28
27
|
def from_et(et_element: ElementTree.Element,
|
29
|
-
doc_frags:
|
28
|
+
doc_frags: list[OdxDocFragment]) -> "MatchingBaseVariantParameter":
|
30
29
|
|
31
30
|
kwargs = dataclass_fields_asdict(MatchingParameter.from_et(et_element, doc_frags))
|
32
31
|
|
odxtools/matchingparameter.py
CHANGED
@@ -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, cast
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .diaglayers.diaglayer import DiagLayer
|
@@ -34,12 +34,12 @@ class MatchingParameter:
|
|
34
34
|
# or negative response. What it probably actually wants to say is
|
35
35
|
# that any response that can possibly be received shall exhibit
|
36
36
|
# the referenced parameter.
|
37
|
-
out_param_if_snref:
|
38
|
-
out_param_if_snpathref:
|
37
|
+
out_param_if_snref: str | None
|
38
|
+
out_param_if_snpathref: str | None
|
39
39
|
|
40
40
|
@staticmethod
|
41
41
|
def from_et(et_element: ElementTree.Element,
|
42
|
-
doc_frags:
|
42
|
+
doc_frags: list[OdxDocFragment]) -> "MatchingParameter":
|
43
43
|
|
44
44
|
expected_value = odxrequire(et_element.findtext("EXPECTED-VALUE"))
|
45
45
|
diag_comm_snref = odxrequire(
|
@@ -61,7 +61,7 @@ class MatchingParameter:
|
|
61
61
|
out_param_if_snpathref=out_param_if_snpathref,
|
62
62
|
)
|
63
63
|
|
64
|
-
def _build_odxlinks(self) ->
|
64
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
65
65
|
return {}
|
66
66
|
|
67
67
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
@@ -93,7 +93,7 @@ class MatchingParameter:
|
|
93
93
|
|
94
94
|
return self.__matches(param_dict, snpath_chunks)
|
95
95
|
|
96
|
-
def __matches(self, param_dict: ParameterValue, snpath_chunks:
|
96
|
+
def __matches(self, param_dict: ParameterValue, snpath_chunks: list[str]) -> bool:
|
97
97
|
if len(snpath_chunks) == 0:
|
98
98
|
parameter_value = param_dict
|
99
99
|
if isinstance(parameter_value, dict):
|
@@ -105,7 +105,7 @@ class MatchingParameter:
|
|
105
105
|
# floating point
|
106
106
|
return abs(float(self.expected_value) - parameter_value) < 1e-8
|
107
107
|
elif isinstance(parameter_value, BytesTypes):
|
108
|
-
return parameter_value.hex().upper() == self.expected_value.upper()
|
108
|
+
return bytes(parameter_value).hex().upper() == self.expected_value.upper()
|
109
109
|
elif isinstance(parameter_value, DiagnosticTroubleCode):
|
110
110
|
# TODO: what happens if non-numerical DTCs like
|
111
111
|
# "U123456" are specified? Is specifying DTCs even
|
odxtools/minmaxlengthtype.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from
|
4
|
-
from typing import List, Optional, cast
|
3
|
+
from typing import cast
|
5
4
|
from xml.etree import ElementTree
|
6
5
|
|
7
6
|
from typing_extensions import override
|
@@ -13,18 +12,13 @@ from .encoding import get_string_encoding
|
|
13
12
|
from .exceptions import DecodeError, EncodeError, odxassert, odxraise, odxrequire
|
14
13
|
from .odxlink import OdxDocFragment
|
15
14
|
from .odxtypes import AtomicOdxType, BytesTypes, DataType
|
15
|
+
from .termination import Termination
|
16
16
|
from .utils import dataclass_fields_asdict
|
17
17
|
|
18
18
|
|
19
|
-
class Termination(Enum):
|
20
|
-
END_OF_PDU = "END-OF-PDU"
|
21
|
-
ZERO = "ZERO"
|
22
|
-
HEX_FF = "HEX-FF"
|
23
|
-
|
24
|
-
|
25
19
|
@dataclass
|
26
20
|
class MinMaxLengthType(DiagCodedType):
|
27
|
-
max_length:
|
21
|
+
max_length: int | None
|
28
22
|
min_length: int
|
29
23
|
termination: Termination
|
30
24
|
|
@@ -35,7 +29,7 @@ class MinMaxLengthType(DiagCodedType):
|
|
35
29
|
@staticmethod
|
36
30
|
@override
|
37
31
|
def from_et(et_element: ElementTree.Element,
|
38
|
-
doc_frags:
|
32
|
+
doc_frags: list[OdxDocFragment]) -> "MinMaxLengthType":
|
39
33
|
kwargs = dataclass_fields_asdict(DiagCodedType.from_et(et_element, doc_frags))
|
40
34
|
|
41
35
|
max_length = None
|
@@ -83,7 +77,7 @@ class MinMaxLengthType(DiagCodedType):
|
|
83
77
|
@override
|
84
78
|
def encode_into_pdu(self, internal_value: AtomicOdxType, encode_state: EncodeState) -> None:
|
85
79
|
|
86
|
-
if not isinstance(internal_value,
|
80
|
+
if not isinstance(internal_value, str | BytesTypes):
|
87
81
|
odxraise("MinMaxLengthType is currently only implemented for strings and byte arrays",
|
88
82
|
EncodeError)
|
89
83
|
|
odxtools/modification.py
CHANGED
@@ -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 .exceptions import odxrequire
|
@@ -11,16 +11,16 @@ from .snrefcontext import SnRefContext
|
|
11
11
|
@dataclass
|
12
12
|
class Modification:
|
13
13
|
change: str
|
14
|
-
reason:
|
14
|
+
reason: str | None
|
15
15
|
|
16
16
|
@staticmethod
|
17
|
-
def from_et(et_element: ElementTree.Element, doc_frags:
|
17
|
+
def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "Modification":
|
18
18
|
change = odxrequire(et_element.findtext("CHANGE"))
|
19
19
|
reason = et_element.findtext("REASON")
|
20
20
|
|
21
21
|
return Modification(change=change, reason=reason)
|
22
22
|
|
23
|
-
def _build_odxlinks(self) ->
|
23
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
24
24
|
return {}
|
25
25
|
|
26
26
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
odxtools/multiplexer.py
CHANGED
@@ -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, cast
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from typing_extensions import override
|
@@ -30,9 +30,9 @@ class Multiplexer(ComplexDop):
|
|
30
30
|
|
31
31
|
byte_position: int
|
32
32
|
switch_key: MultiplexerSwitchKey
|
33
|
-
default_case:
|
33
|
+
default_case: MultiplexerDefaultCase | None
|
34
34
|
cases: NamedItemList[MultiplexerCase]
|
35
|
-
is_visible_raw:
|
35
|
+
is_visible_raw: bool | None
|
36
36
|
|
37
37
|
@property
|
38
38
|
def is_visible(self) -> bool:
|
@@ -40,7 +40,7 @@ class Multiplexer(ComplexDop):
|
|
40
40
|
|
41
41
|
@staticmethod
|
42
42
|
@override
|
43
|
-
def from_et(et_element: ElementTree.Element, doc_frags:
|
43
|
+
def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "Multiplexer":
|
44
44
|
"""Reads a Multiplexer from Diag Layer."""
|
45
45
|
kwargs = dataclass_fields_asdict(ComplexDop.from_et(et_element, doc_frags))
|
46
46
|
|
@@ -66,7 +66,7 @@ class Multiplexer(ComplexDop):
|
|
66
66
|
**kwargs)
|
67
67
|
|
68
68
|
@override
|
69
|
-
def _build_odxlinks(self) ->
|
69
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
70
70
|
odxlinks = super()._build_odxlinks()
|
71
71
|
|
72
72
|
odxlinks.update(self.switch_key._build_odxlinks())
|
@@ -98,7 +98,7 @@ class Multiplexer(ComplexDop):
|
|
98
98
|
for mux_case in self.cases:
|
99
99
|
mux_case._resolve_snrefs(context)
|
100
100
|
|
101
|
-
def _get_case_limits(self, case: MultiplexerCase) ->
|
101
|
+
def _get_case_limits(self, case: MultiplexerCase) -> tuple[AtomicOdxType, AtomicOdxType]:
|
102
102
|
key_type = self.switch_key.dop.physical_type.base_data_type
|
103
103
|
lower_limit = key_type.make_from(case.lower_limit.value)
|
104
104
|
upper_limit = key_type.make_from(case.upper_limit.value)
|
@@ -118,7 +118,7 @@ class Multiplexer(ComplexDop):
|
|
118
118
|
orig_origin = encode_state.origin_byte_position
|
119
119
|
encode_state.origin_byte_position = encode_state.cursor_byte_position
|
120
120
|
|
121
|
-
if isinstance(physical_value,
|
121
|
+
if isinstance(physical_value, list | tuple) and len(physical_value) == 2:
|
122
122
|
case_spec, case_value = physical_value
|
123
123
|
elif isinstance(physical_value, dict) and len(physical_value) == 1:
|
124
124
|
case_spec, case_value = next(iter(physical_value.items()))
|
@@ -127,8 +127,8 @@ class Multiplexer(ComplexDop):
|
|
127
127
|
f"Values of multiplexer parameters must be defined as a "
|
128
128
|
f"(case_name, content_value) tuple instead of as '{physical_value!r}'")
|
129
129
|
|
130
|
-
mux_case:
|
131
|
-
applicable_cases:
|
130
|
+
mux_case: MultiplexerCase | MultiplexerDefaultCase
|
131
|
+
applicable_cases: list[MultiplexerCase | MultiplexerDefaultCase]
|
132
132
|
|
133
133
|
if isinstance(case_spec, str):
|
134
134
|
applicable_cases = [x for x in self.cases if x.short_name == case_spec]
|
@@ -147,7 +147,7 @@ class Multiplexer(ComplexDop):
|
|
147
147
|
elif isinstance(case_spec, int):
|
148
148
|
applicable_cases = []
|
149
149
|
for x in self.cases:
|
150
|
-
lower, upper = cast(
|
150
|
+
lower, upper = cast(tuple[int, int], self._get_case_limits(x))
|
151
151
|
if lower <= case_spec and case_spec <= upper:
|
152
152
|
applicable_cases.append(x)
|
153
153
|
|
@@ -208,7 +208,7 @@ class Multiplexer(ComplexDop):
|
|
208
208
|
# relatively to the byte position of the MUX."
|
209
209
|
decode_state.cursor_byte_position = decode_state.origin_byte_position + self.byte_position
|
210
210
|
|
211
|
-
applicable_case:
|
211
|
+
applicable_case: MultiplexerCase | MultiplexerDefaultCase | None = None
|
212
212
|
for mux_case in self.cases:
|
213
213
|
lower, upper = self._get_case_limits(mux_case)
|
214
214
|
if lower <= key_value and key_value <= upper: # type: ignore[operator]
|
odxtools/multiplexercase.py
CHANGED
@@ -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 .compumethods.limit import Limit
|
@@ -17,18 +17,18 @@ from .utils import dataclass_fields_asdict
|
|
17
17
|
class MultiplexerCase(NamedElement):
|
18
18
|
"""This class represents a case which represents a range of keys of a multiplexer."""
|
19
19
|
|
20
|
-
structure_ref:
|
21
|
-
structure_snref:
|
20
|
+
structure_ref: OdxLinkRef | None
|
21
|
+
structure_snref: str | None
|
22
22
|
lower_limit: Limit
|
23
23
|
upper_limit: Limit
|
24
24
|
|
25
25
|
@property
|
26
|
-
def structure(self) ->
|
26
|
+
def structure(self) -> Structure | None:
|
27
27
|
return self._structure
|
28
28
|
|
29
29
|
@staticmethod
|
30
30
|
def from_et(et_element: ElementTree.Element,
|
31
|
-
doc_frags:
|
31
|
+
doc_frags: list[OdxDocFragment]) -> "MultiplexerCase":
|
32
32
|
"""Reads a case for a Multiplexer."""
|
33
33
|
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
|
34
34
|
structure_ref = OdxLinkRef.from_et(et_element.find("STRUCTURE-REF"), doc_frags)
|
@@ -54,7 +54,7 @@ class MultiplexerCase(NamedElement):
|
|
54
54
|
upper_limit=upper_limit,
|
55
55
|
**kwargs)
|
56
56
|
|
57
|
-
def _build_odxlinks(self) ->
|
57
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
58
58
|
return {}
|
59
59
|
|
60
60
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
@@ -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 NamedElement
|
@@ -14,16 +14,16 @@ from .utils import dataclass_fields_asdict
|
|
14
14
|
@dataclass
|
15
15
|
class MultiplexerDefaultCase(NamedElement):
|
16
16
|
"""This class represents a Default Case, which is selected when there are no cases defined in the Multiplexer."""
|
17
|
-
structure_ref:
|
18
|
-
structure_snref:
|
17
|
+
structure_ref: OdxLinkRef | None
|
18
|
+
structure_snref: str | None
|
19
19
|
|
20
20
|
@property
|
21
|
-
def structure(self) ->
|
21
|
+
def structure(self) -> Structure | None:
|
22
22
|
return self._structure
|
23
23
|
|
24
24
|
@staticmethod
|
25
25
|
def from_et(et_element: ElementTree.Element,
|
26
|
-
doc_frags:
|
26
|
+
doc_frags: list[OdxDocFragment]) -> "MultiplexerDefaultCase":
|
27
27
|
"""Reads a default case for a multiplexer."""
|
28
28
|
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
|
29
29
|
|
@@ -35,7 +35,7 @@ class MultiplexerDefaultCase(NamedElement):
|
|
35
35
|
return MultiplexerDefaultCase(
|
36
36
|
structure_ref=structure_ref, structure_snref=structure_snref, **kwargs)
|
37
37
|
|
38
|
-
def _build_odxlinks(self) ->
|
38
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
39
39
|
return {}
|
40
40
|
|
41
41
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|