odxtools 5.3.1__py3-none-any.whl → 6.0.1__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 +1 -1
- odxtools/basicstructure.py +76 -91
- odxtools/cli/_parser_utils.py +12 -9
- odxtools/cli/_print_utils.py +7 -7
- odxtools/cli/browse.py +94 -73
- odxtools/cli/find.py +42 -59
- odxtools/cli/list.py +21 -17
- odxtools/cli/snoop.py +19 -18
- odxtools/communicationparameterref.py +6 -3
- odxtools/companydocinfo.py +2 -2
- odxtools/companyrevisioninfo.py +1 -1
- odxtools/comparamsubset.py +6 -6
- odxtools/complexcomparam.py +1 -1
- odxtools/compumethods/compumethod.py +6 -9
- odxtools/compumethods/createanycompumethod.py +11 -9
- odxtools/compumethods/identicalcompumethod.py +5 -4
- odxtools/compumethods/limit.py +9 -9
- odxtools/compumethods/linearcompumethod.py +25 -17
- odxtools/compumethods/scalelinearcompumethod.py +6 -5
- odxtools/compumethods/tabintpcompumethod.py +30 -9
- odxtools/compumethods/texttablecompumethod.py +22 -24
- odxtools/database.py +5 -5
- odxtools/dataobjectproperty.py +10 -23
- odxtools/decodestate.py +1 -1
- odxtools/determinenumberofitems.py +37 -8
- odxtools/diagcodedtype.py +14 -9
- odxtools/diagdatadictionaryspec.py +60 -37
- odxtools/diaglayer.py +30 -21
- odxtools/diaglayercontainer.py +40 -40
- odxtools/diaglayerraw.py +92 -63
- odxtools/diagnostictroublecode.py +2 -2
- odxtools/diagservice.py +53 -35
- odxtools/docrevision.py +1 -1
- odxtools/dopbase.py +14 -3
- odxtools/dtcdop.py +15 -9
- odxtools/dynamiclengthfield.py +6 -4
- odxtools/endofpdufield.py +22 -23
- odxtools/environmentdata.py +2 -5
- odxtools/environmentdatadescription.py +6 -4
- odxtools/field.py +3 -8
- odxtools/isotp_state_machine.py +52 -38
- odxtools/leadinglengthinfotype.py +9 -7
- odxtools/load_file.py +2 -1
- odxtools/load_odx_d_file.py +2 -5
- odxtools/load_pdx_file.py +2 -6
- odxtools/message.py +11 -3
- odxtools/minmaxlengthtype.py +107 -78
- odxtools/modification.py +2 -2
- odxtools/multiplexer.py +23 -21
- odxtools/multiplexerswitchkey.py +37 -8
- odxtools/nameditemlist.py +59 -58
- odxtools/odxlink.py +4 -2
- odxtools/odxtypes.py +4 -3
- odxtools/parameterinfo.py +6 -6
- odxtools/parameters/codedconstparameter.py +15 -25
- odxtools/parameters/createanyparameter.py +1 -1
- odxtools/parameters/dynamicparameter.py +6 -5
- odxtools/parameters/lengthkeyparameter.py +2 -1
- odxtools/parameters/matchingrequestparameter.py +8 -11
- odxtools/parameters/nrcconstparameter.py +11 -21
- odxtools/parameters/parameter.py +4 -18
- odxtools/parameters/parameterwithdop.py +14 -29
- odxtools/parameters/physicalconstantparameter.py +7 -9
- odxtools/parameters/reservedparameter.py +17 -38
- odxtools/parameters/systemparameter.py +6 -5
- odxtools/parameters/tableentryparameter.py +6 -5
- odxtools/parameters/tablekeyparameter.py +8 -15
- odxtools/parameters/tablestructparameter.py +11 -12
- odxtools/parameters/valueparameter.py +9 -24
- odxtools/paramlengthinfotype.py +11 -9
- odxtools/physicaldimension.py +1 -1
- odxtools/physicaltype.py +2 -2
- odxtools/response.py +7 -3
- odxtools/singleecujob.py +48 -22
- odxtools/standardlengthtype.py +11 -6
- odxtools/uds.py +1 -1
- odxtools/unit.py +5 -5
- odxtools/unitgroup.py +1 -1
- odxtools/unitspec.py +2 -2
- odxtools/version.py +13 -3
- odxtools/write_pdx_file.py +7 -4
- {odxtools-5.3.1.dist-info → odxtools-6.0.1.dist-info}/METADATA +7 -5
- {odxtools-5.3.1.dist-info → odxtools-6.0.1.dist-info}/RECORD +87 -88
- odxtools/positioneddataobjectproperty.py +0 -74
- {odxtools-5.3.1.dist-info → odxtools-6.0.1.dist-info}/LICENSE +0 -0
- {odxtools-5.3.1.dist-info → odxtools-6.0.1.dist-info}/WHEEL +0 -0
- {odxtools-5.3.1.dist-info → odxtools-6.0.1.dist-info}/entry_points.txt +0 -0
- {odxtools-5.3.1.dist-info → odxtools-6.0.1.dist-info}/top_level.txt +0 -0
odxtools/odxlink.py
CHANGED
@@ -153,7 +153,7 @@ class OdxLinkRef:
|
|
153
153
|
|
154
154
|
# we must reference at to at least of the ID's document
|
155
155
|
# fragments
|
156
|
-
if not any(
|
156
|
+
if not any(ref_doc in odx_id.doc_fragments for ref_doc in self.ref_docs):
|
157
157
|
return False
|
158
158
|
|
159
159
|
# the local ID of the reference and the object ID must match
|
@@ -199,6 +199,7 @@ class OdxLinkDatabase:
|
|
199
199
|
f"Warning: Unknown document fragment {ref_frag} "
|
200
200
|
f"when resolving reference {ref}",
|
201
201
|
OdxWarning,
|
202
|
+
stacklevel=1,
|
202
203
|
)
|
203
204
|
continue
|
204
205
|
|
@@ -241,6 +242,7 @@ class OdxLinkDatabase:
|
|
241
242
|
f"Warning: Unknown document fragment {ref_frag} "
|
242
243
|
f"when resolving reference {ref}",
|
243
244
|
OdxWarning,
|
245
|
+
stacklevel=1,
|
244
246
|
)
|
245
247
|
continue
|
246
248
|
|
@@ -265,6 +267,6 @@ class OdxLinkDatabase:
|
|
265
267
|
for odx_id, obj in new_entries.items():
|
266
268
|
for doc_frag in odx_id.doc_fragments:
|
267
269
|
if doc_frag not in self._db:
|
268
|
-
self._db[doc_frag] =
|
270
|
+
self._db[doc_frag] = {}
|
269
271
|
|
270
272
|
self._db[doc_frag][odx_id] = obj
|
odxtools/odxtypes.py
CHANGED
@@ -6,12 +6,13 @@ from xml.etree import ElementTree
|
|
6
6
|
from .exceptions import odxassert, odxraise, odxrequire
|
7
7
|
|
8
8
|
if TYPE_CHECKING:
|
9
|
-
from .
|
9
|
+
from odxtools.diagnostictroublecode import DiagnosticTroubleCode
|
10
|
+
from odxtools.parameters.parameter import Parameter
|
10
11
|
|
11
12
|
|
12
13
|
def bytefield_to_bytearray(bytefield: str) -> bytearray:
|
13
14
|
bytes_string = [bytefield[i:i + 2] for i in range(0, len(bytefield), 2)]
|
14
|
-
return bytearray(
|
15
|
+
return bytearray([int(x, 16) for x in bytes_string])
|
15
16
|
|
16
17
|
|
17
18
|
AtomicOdxType = Union[str, int, float, bytes]
|
@@ -27,7 +28,7 @@ ParameterDict = Dict[str, Union["Parameter", "ParameterDict"]]
|
|
27
28
|
# multiple items, so this can be a list of objects.
|
28
29
|
TableStructParameterValue = Tuple[str, "ParameterValue"]
|
29
30
|
ParameterValue = Union[AtomicOdxType, "ParameterValueDict", TableStructParameterValue,
|
30
|
-
List["ParameterValue"]]
|
31
|
+
List["ParameterValue"], "DiagnosticTroubleCode"]
|
31
32
|
ParameterValueDict = Dict[str, ParameterValue]
|
32
33
|
|
33
34
|
|
odxtools/parameterinfo.py
CHANGED
@@ -75,10 +75,10 @@ def parameter_info(param_list: Iterable[Union[Parameter, EndOfPduField]]) -> str
|
|
75
75
|
else:
|
76
76
|
result += f": <unknown type>"
|
77
77
|
|
78
|
-
if dop.
|
79
|
-
result += f"{
|
80
|
-
|
81
|
-
|
78
|
+
if (bl := dop.get_static_bit_length()) is not None:
|
79
|
+
result += f"{bl}"
|
80
|
+
|
81
|
+
result += "\n"
|
82
82
|
|
83
83
|
elif isinstance(cm, LinearCompuMethod):
|
84
84
|
result += f": float\n"
|
@@ -86,8 +86,8 @@ def parameter_info(param_list: Iterable[Union[Parameter, EndOfPduField]]) -> str
|
|
86
86
|
ul = cm.physical_upper_limit
|
87
87
|
result += (f" range: "
|
88
88
|
f"{'[' if ll.interval_type == IntervalType.CLOSED else '('}"
|
89
|
-
f"{ll.value}, "
|
90
|
-
f"{ul.value}"
|
89
|
+
f"{ll.value!r}, "
|
90
|
+
f"{ul.value!r}"
|
91
91
|
f"{']' if ul.interval_type == IntervalType.CLOSED else ')'}\n")
|
92
92
|
|
93
93
|
unit = dop.unit
|
@@ -2,7 +2,7 @@
|
|
2
2
|
import warnings
|
3
3
|
from copy import copy
|
4
4
|
from dataclasses import dataclass
|
5
|
-
from typing import TYPE_CHECKING, Any, Dict
|
5
|
+
from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple
|
6
6
|
|
7
7
|
from ..decodestate import DecodeState
|
8
8
|
from ..diagcodedtype import DiagCodedType
|
@@ -39,9 +39,8 @@ class CodedConstParameter(Parameter):
|
|
39
39
|
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
40
40
|
super()._resolve_snrefs(diag_layer)
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
return self.diag_coded_type.bit_length
|
42
|
+
def get_static_bit_length(self) -> Optional[int]:
|
43
|
+
return getattr(self.diag_coded_type, "bit_length", None)
|
45
44
|
|
46
45
|
@property
|
47
46
|
def internal_data_type(self) -> DataType:
|
@@ -55,10 +54,7 @@ class CodedConstParameter(Parameter):
|
|
55
54
|
def is_settable(self) -> bool:
|
56
55
|
return False
|
57
56
|
|
58
|
-
def
|
59
|
-
return self.coded_value
|
60
|
-
|
61
|
-
def get_coded_value_as_bytes(self, encode_state: EncodeState):
|
57
|
+
def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
|
62
58
|
if (self.short_name in encode_state.parameter_values and
|
63
59
|
encode_state.parameter_values[self.short_name] != self.coded_value):
|
64
60
|
raise TypeError(f"The parameter '{self.short_name}' is constant {self._coded_value_str}"
|
@@ -67,15 +63,15 @@ class CodedConstParameter(Parameter):
|
|
67
63
|
return self.diag_coded_type.convert_internal_to_bytes(
|
68
64
|
self.coded_value, encode_state=encode_state, bit_position=bit_position_int)
|
69
65
|
|
70
|
-
def decode_from_pdu(self, decode_state: DecodeState):
|
66
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[AtomicOdxType, int]:
|
71
67
|
decode_state = copy(decode_state)
|
72
|
-
if self.byte_position is not None and self.byte_position != decode_state.
|
68
|
+
if self.byte_position is not None and self.byte_position != decode_state.cursor_position:
|
73
69
|
# Update byte position
|
74
|
-
decode_state.
|
70
|
+
decode_state.cursor_position = self.byte_position
|
75
71
|
|
76
72
|
# Extract coded values
|
77
73
|
bit_position_int = self.bit_position if self.bit_position is not None else 0
|
78
|
-
coded_val,
|
74
|
+
coded_val, cursor_position = self.diag_coded_type.convert_bytes_to_internal(
|
79
75
|
decode_state, bit_position=bit_position_int)
|
80
76
|
|
81
77
|
# Check if the coded value in the message is correct.
|
@@ -84,25 +80,19 @@ class CodedConstParameter(Parameter):
|
|
84
80
|
f"Coded constant parameter does not match! "
|
85
81
|
f"The parameter {self.short_name} expected coded "
|
86
82
|
f"value {str(self._coded_value_str)} but got {str(coded_val)} "
|
87
|
-
f"at byte position {decode_state.
|
83
|
+
f"at byte position {decode_state.cursor_position} "
|
88
84
|
f"in coded message {decode_state.coded_message.hex()}.",
|
89
85
|
DecodeError,
|
86
|
+
stacklevel=1,
|
90
87
|
)
|
91
88
|
|
92
|
-
return coded_val,
|
93
|
-
|
94
|
-
def _as_dict(self):
|
95
|
-
d = super()._as_dict()
|
96
|
-
if self.bit_length is not None:
|
97
|
-
d["bit_length"] = self.bit_length
|
98
|
-
d["coded_value"] = hex(self.coded_value)
|
99
|
-
return d
|
89
|
+
return coded_val, cursor_position
|
100
90
|
|
101
91
|
@property
|
102
|
-
def _coded_value_str(self):
|
103
|
-
if isinstance(self.coded_value,
|
104
|
-
return
|
105
|
-
return self.coded_value
|
92
|
+
def _coded_value_str(self) -> str:
|
93
|
+
if isinstance(self.coded_value, bytes):
|
94
|
+
return self.coded_value.hex()
|
95
|
+
return str(self.coded_value)
|
106
96
|
|
107
97
|
def get_description_of_valid_values(self) -> str:
|
108
98
|
"""return a human-understandable description of valid physical values"""
|
@@ -115,7 +115,7 @@ def create_any_parameter_from_et(et_element: ElementTree.Element,
|
|
115
115
|
bit_length = int(odxrequire(et_element.findtext("BIT-LENGTH")))
|
116
116
|
|
117
117
|
return ReservedParameter(
|
118
|
-
|
118
|
+
bit_length=bit_length,
|
119
119
|
semantic=semantic,
|
120
120
|
byte_position=byte_position,
|
121
121
|
bit_position=bit_position,
|
@@ -1,6 +1,10 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
+
from typing import Tuple
|
3
4
|
|
5
|
+
from ..decodestate import DecodeState
|
6
|
+
from ..encodestate import EncodeState
|
7
|
+
from ..odxtypes import ParameterValue
|
4
8
|
from .parameter import Parameter, ParameterType
|
5
9
|
|
6
10
|
|
@@ -19,11 +23,8 @@ class DynamicParameter(Parameter):
|
|
19
23
|
def is_settable(self) -> bool:
|
20
24
|
raise NotImplementedError(".is_settable for a DynamicParameter")
|
21
25
|
|
22
|
-
def
|
26
|
+
def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
|
23
27
|
raise NotImplementedError("Encoding a DynamicParameter is not implemented yet.")
|
24
28
|
|
25
|
-
def
|
26
|
-
raise NotImplementedError("Encoding a DynamicParameter is not implemented yet.")
|
27
|
-
|
28
|
-
def decode_from_pdu(self, coded_message, default_byte_position=None):
|
29
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[ParameterValue, int]:
|
29
30
|
raise NotImplementedError("Decoding a DynamicParameter is not implemented yet.")
|
@@ -6,6 +6,7 @@ from ..decodestate import DecodeState
|
|
6
6
|
from ..encodestate import EncodeState
|
7
7
|
from ..exceptions import odxrequire
|
8
8
|
from ..odxlink import OdxLinkDatabase, OdxLinkId
|
9
|
+
from ..odxtypes import ParameterValue
|
9
10
|
from .parameter import ParameterType
|
10
11
|
from .parameterwithdop import ParameterWithDOP
|
11
12
|
|
@@ -65,5 +66,5 @@ class LengthKeyParameter(ParameterWithDOP):
|
|
65
66
|
def encode_into_pdu(self, encode_state: EncodeState) -> bytes:
|
66
67
|
return super().encode_into_pdu(encode_state)
|
67
68
|
|
68
|
-
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[
|
69
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[ParameterValue, int]:
|
69
70
|
return super().decode_from_pdu(decode_state)
|
@@ -1,9 +1,11 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
+
from typing import Optional, Tuple
|
3
4
|
|
4
5
|
from ..decodestate import DecodeState
|
5
6
|
from ..encodestate import EncodeState
|
6
7
|
from ..exceptions import EncodeError
|
8
|
+
from ..odxtypes import ParameterValue
|
7
9
|
from .parameter import Parameter, ParameterType
|
8
10
|
|
9
11
|
|
@@ -16,8 +18,7 @@ class MatchingRequestParameter(Parameter):
|
|
16
18
|
def parameter_type(self) -> ParameterType:
|
17
19
|
return "MATCHING-REQUEST-PARAM"
|
18
20
|
|
19
|
-
|
20
|
-
def bit_length(self):
|
21
|
+
def get_static_bit_length(self) -> Optional[int]:
|
21
22
|
return 8 * self.byte_length
|
22
23
|
|
23
24
|
@property
|
@@ -28,10 +29,7 @@ class MatchingRequestParameter(Parameter):
|
|
28
29
|
def is_settable(self) -> bool:
|
29
30
|
return False
|
30
31
|
|
31
|
-
def
|
32
|
-
return request_value
|
33
|
-
|
34
|
-
def get_coded_value_as_bytes(self, encode_state: EncodeState):
|
32
|
+
def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
|
35
33
|
if not encode_state.triggering_request:
|
36
34
|
raise EncodeError(f"Parameter '{self.short_name}' is of matching request type,"
|
37
35
|
" but no original request has been specified.")
|
@@ -39,12 +37,11 @@ class MatchingRequestParameter(Parameter):
|
|
39
37
|
.request_byte_position:self.request_byte_position +
|
40
38
|
self.byte_length]
|
41
39
|
|
42
|
-
def decode_from_pdu(self, decode_state: DecodeState):
|
40
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[ParameterValue, int]:
|
43
41
|
byte_position = (
|
44
|
-
self.byte_position
|
45
|
-
|
46
|
-
|
47
|
-
byte_length = (self.bit_length + bit_position + 7) // 8
|
42
|
+
self.byte_position if self.byte_position is not None else decode_state.cursor_position)
|
43
|
+
bit_position = self.bit_position or 0
|
44
|
+
byte_length = (8 * self.byte_length + bit_position + 7) // 8
|
48
45
|
val_as_bytes = decode_state.coded_message[byte_position:byte_position + byte_length]
|
49
46
|
|
50
47
|
return val_as_bytes, byte_position + byte_length
|
@@ -2,7 +2,7 @@
|
|
2
2
|
import warnings
|
3
3
|
from copy import copy
|
4
4
|
from dataclasses import dataclass
|
5
|
-
from typing import TYPE_CHECKING, Any, Dict, List
|
5
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
|
6
6
|
|
7
7
|
from ..decodestate import DecodeState
|
8
8
|
from ..diagcodedtype import DiagCodedType
|
@@ -47,9 +47,8 @@ class NrcConstParameter(Parameter):
|
|
47
47
|
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
48
48
|
super()._resolve_snrefs(diag_layer)
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
return self.diag_coded_type.bit_length
|
50
|
+
def get_static_bit_length(self) -> Optional[int]:
|
51
|
+
return self.diag_coded_type.get_static_bit_length()
|
53
52
|
|
54
53
|
@property
|
55
54
|
def internal_data_type(self) -> DataType:
|
@@ -63,10 +62,7 @@ class NrcConstParameter(Parameter):
|
|
63
62
|
def is_settable(self) -> bool:
|
64
63
|
return False
|
65
64
|
|
66
|
-
def
|
67
|
-
return self.coded_value
|
68
|
-
|
69
|
-
def get_coded_value_as_bytes(self, encode_state: EncodeState):
|
65
|
+
def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
|
70
66
|
if self.short_name in encode_state.parameter_values:
|
71
67
|
if encode_state.parameter_values[self.short_name] not in self.coded_values:
|
72
68
|
raise EncodeError(f"The parameter '{self.short_name}' must have"
|
@@ -82,15 +78,15 @@ class NrcConstParameter(Parameter):
|
|
82
78
|
return self.diag_coded_type.convert_internal_to_bytes(
|
83
79
|
coded_value, encode_state, bit_position=bit_position_int)
|
84
80
|
|
85
|
-
def decode_from_pdu(self, decode_state: DecodeState):
|
81
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[AtomicOdxType, int]:
|
86
82
|
decode_state = copy(decode_state)
|
87
|
-
if self.byte_position is not None and self.byte_position != decode_state.
|
83
|
+
if self.byte_position is not None and self.byte_position != decode_state.cursor_position:
|
88
84
|
# Update byte position
|
89
|
-
decode_state.
|
85
|
+
decode_state.cursor_position = self.byte_position
|
90
86
|
|
91
87
|
# Extract coded values
|
92
88
|
bit_position_int = self.bit_position if self.bit_position is not None else 0
|
93
|
-
coded_value,
|
89
|
+
coded_value, cursor_position = self.diag_coded_type.convert_bytes_to_internal(
|
94
90
|
decode_state, bit_position=bit_position_int)
|
95
91
|
|
96
92
|
# Check if the coded value in the message is correct.
|
@@ -99,19 +95,13 @@ class NrcConstParameter(Parameter):
|
|
99
95
|
f"Coded constant parameter does not match! "
|
100
96
|
f"The parameter {self.short_name} expected a coded "
|
101
97
|
f"value in {str(self.coded_values)} but got {str(coded_value)} "
|
102
|
-
f"at byte position {decode_state.
|
98
|
+
f"at byte position {decode_state.cursor_position} "
|
103
99
|
f"in coded message {decode_state.coded_message.hex()}.",
|
104
100
|
DecodeError,
|
101
|
+
stacklevel=1,
|
105
102
|
)
|
106
103
|
|
107
|
-
return coded_value,
|
108
|
-
|
109
|
-
def _as_dict(self):
|
110
|
-
d = super()._as_dict()
|
111
|
-
if self.bit_length is not None:
|
112
|
-
d["bit_length"] = self.bit_length
|
113
|
-
d["coded_values"] = self.coded_values
|
114
|
-
return d
|
104
|
+
return coded_value, cursor_position
|
115
105
|
|
116
106
|
def get_description_of_valid_values(self) -> str:
|
117
107
|
"""return a human-understandable description of valid physical values"""
|
odxtools/parameters/parameter.py
CHANGED
@@ -9,6 +9,7 @@ from ..element import NamedElement
|
|
9
9
|
from ..encodestate import EncodeState
|
10
10
|
from ..exceptions import OdxWarning
|
11
11
|
from ..odxlink import OdxLinkDatabase, OdxLinkId
|
12
|
+
from ..odxtypes import ParameterValue
|
12
13
|
from ..specialdatagroup import SpecialDataGroup
|
13
14
|
|
14
15
|
if TYPE_CHECKING:
|
@@ -58,8 +59,7 @@ class Parameter(NamedElement, abc.ABC):
|
|
58
59
|
def parameter_type(self) -> ParameterType:
|
59
60
|
pass
|
60
61
|
|
61
|
-
|
62
|
-
def bit_length(self) -> Optional[int]:
|
62
|
+
def get_static_bit_length(self) -> Optional[int]:
|
63
63
|
return None
|
64
64
|
|
65
65
|
@property
|
@@ -85,10 +85,6 @@ class Parameter(NamedElement, abc.ABC):
|
|
85
85
|
"""
|
86
86
|
raise NotImplementedError
|
87
87
|
|
88
|
-
@abc.abstractmethod
|
89
|
-
def get_coded_value(self):
|
90
|
-
pass
|
91
|
-
|
92
88
|
@abc.abstractmethod
|
93
89
|
def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
|
94
90
|
"""Get the coded value of the parameter given the encode state.
|
@@ -97,7 +93,7 @@ class Parameter(NamedElement, abc.ABC):
|
|
97
93
|
pass
|
98
94
|
|
99
95
|
@abc.abstractmethod
|
100
|
-
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[
|
96
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[ParameterValue, int]:
|
101
97
|
"""Decode the parameter value from the coded message.
|
102
98
|
|
103
99
|
If the parameter does have a byte position property, the coded bytes the parameter covers are extracted
|
@@ -178,18 +174,8 @@ class Parameter(NamedElement, abc.ABC):
|
|
178
174
|
warnings.warn(
|
179
175
|
f"Parameter {self.short_name} overlaps with another parameter (bytes are already set)",
|
180
176
|
OdxWarning,
|
177
|
+
stacklevel=1,
|
181
178
|
)
|
182
179
|
result_blob[byte_idx_rpc] |= new_data[byte_idx_val]
|
183
180
|
|
184
181
|
return result_blob
|
185
|
-
|
186
|
-
def _as_dict(self):
|
187
|
-
"""
|
188
|
-
Mostly for pretty printing purposes (specifically not for reconstructing the object)
|
189
|
-
"""
|
190
|
-
d = {"short_name": self.short_name, "type": self.parameter_type, "semantic": self.semantic}
|
191
|
-
if self.byte_position is not None:
|
192
|
-
d["byte_position"] = self.byte_position
|
193
|
-
if self.bit_position is not None:
|
194
|
-
d["bit_position"] = self.bit_position
|
195
|
-
return d
|
@@ -10,6 +10,7 @@ from ..dtcdop import DtcDop
|
|
10
10
|
from ..encodestate import EncodeState
|
11
11
|
from ..exceptions import odxassert, odxrequire
|
12
12
|
from ..odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
13
|
+
from ..odxtypes import ParameterValue
|
13
14
|
from ..physicaltype import PhysicalType
|
14
15
|
from .parameter import Parameter
|
15
16
|
|
@@ -54,15 +55,16 @@ class ParameterWithDOP(Parameter):
|
|
54
55
|
spec.env_datas.get(self.dop_snref))
|
55
56
|
|
56
57
|
@property
|
57
|
-
def dop(self) ->
|
58
|
+
def dop(self) -> DopBase:
|
58
59
|
"""may be a DataObjectProperty, a Structure or None"""
|
59
60
|
|
60
|
-
return
|
61
|
+
return odxrequire(
|
62
|
+
self._dop, "Specifying a data object property is mandatory but it "
|
63
|
+
"could not be resolved")
|
61
64
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
return self.dop.bit_length
|
65
|
+
def get_static_bit_length(self) -> Optional[int]:
|
66
|
+
if self._dop is not None:
|
67
|
+
return self._dop.get_static_bit_length()
|
66
68
|
else:
|
67
69
|
return None
|
68
70
|
|
@@ -73,38 +75,21 @@ class ParameterWithDOP(Parameter):
|
|
73
75
|
else:
|
74
76
|
return None
|
75
77
|
|
76
|
-
def
|
77
|
-
return self.dop.convert_physical_to_internal(physical_value)
|
78
|
-
|
79
|
-
def get_coded_value_as_bytes(self, encode_state: EncodeState):
|
78
|
+
def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
|
80
79
|
dop = odxrequire(self.dop, "Reference to DOP is not resolved")
|
81
80
|
physical_value = encode_state.parameter_values[self.short_name]
|
82
81
|
bit_position_int = self.bit_position if self.bit_position is not None else 0
|
83
82
|
return dop.convert_physical_to_bytes(
|
84
83
|
physical_value, encode_state, bit_position=bit_position_int)
|
85
84
|
|
86
|
-
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[
|
87
|
-
dop = odxrequire(self.dop, "Reference to DOP is not resolved")
|
85
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[ParameterValue, int]:
|
88
86
|
decode_state = copy(decode_state)
|
89
|
-
if self.byte_position is not None and self.byte_position != decode_state.
|
90
|
-
decode_state.
|
87
|
+
if self.byte_position is not None and self.byte_position != decode_state.cursor_position:
|
88
|
+
decode_state.cursor_position = self.byte_position
|
91
89
|
|
92
90
|
# Use DOP to decode
|
93
91
|
bit_position_int = self.bit_position if self.bit_position is not None else 0
|
94
|
-
phys_val,
|
92
|
+
phys_val, cursor_position = self.dop.convert_bytes_to_physical(
|
95
93
|
decode_state, bit_position=bit_position_int)
|
96
94
|
|
97
|
-
return phys_val,
|
98
|
-
|
99
|
-
def _as_dict(self):
|
100
|
-
d = super()._as_dict()
|
101
|
-
if self.dop is not None:
|
102
|
-
if self.bit_length is not None:
|
103
|
-
d["bit_length"] = self.bit_length
|
104
|
-
d["dop_ref"] = OdxLinkRef.from_id(self.dop.odx_id)
|
105
|
-
elif self.dop_ref is not None:
|
106
|
-
d["dop_ref"] = self.dop_ref
|
107
|
-
elif self.dop_snref is not None:
|
108
|
-
d["dop_snref"] = self.dop_snref
|
109
|
-
|
110
|
-
return d
|
95
|
+
return phys_val, cursor_position
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
import warnings
|
3
3
|
from dataclasses import dataclass
|
4
|
-
from typing import TYPE_CHECKING, Any, Dict
|
4
|
+
from typing import TYPE_CHECKING, Any, Dict, Tuple
|
5
5
|
|
6
6
|
from ..dataobjectproperty import DataObjectProperty
|
7
7
|
from ..decodestate import DecodeState
|
@@ -52,10 +52,7 @@ class PhysicalConstantParameter(ParameterWithDOP):
|
|
52
52
|
def is_settable(self) -> bool:
|
53
53
|
return False
|
54
54
|
|
55
|
-
def
|
56
|
-
return self.dop.convert_physical_to_internal(self.physical_constant_value)
|
57
|
-
|
58
|
-
def get_coded_value_as_bytes(self, encode_state: EncodeState):
|
55
|
+
def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
|
59
56
|
dop = odxrequire(self.dop, "Reference to DOP is not resolved")
|
60
57
|
if (self.short_name in encode_state.parameter_values and
|
61
58
|
encode_state.parameter_values[self.short_name] != self.physical_constant_value):
|
@@ -67,17 +64,18 @@ class PhysicalConstantParameter(ParameterWithDOP):
|
|
67
64
|
return dop.convert_physical_to_bytes(
|
68
65
|
self.physical_constant_value, encode_state, bit_position=bit_position_int)
|
69
66
|
|
70
|
-
def decode_from_pdu(self, decode_state: DecodeState):
|
67
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[ParameterValue, int]:
|
71
68
|
# Decode value
|
72
|
-
phys_val,
|
69
|
+
phys_val, cursor_position = super().decode_from_pdu(decode_state)
|
73
70
|
|
74
71
|
# Check if decoded value matches expected value
|
75
72
|
if phys_val != self.physical_constant_value:
|
76
73
|
warnings.warn(
|
77
74
|
f"Physical constant parameter does not match! "
|
78
75
|
f"The parameter {self.short_name} expected physical value {self.physical_constant_value!r} but got {phys_val!r} "
|
79
|
-
f"at byte position {
|
76
|
+
f"at byte position {cursor_position} "
|
80
77
|
f"in coded message {decode_state.coded_message.hex()}.",
|
81
78
|
DecodeError,
|
79
|
+
stacklevel=1,
|
82
80
|
)
|
83
|
-
return phys_val,
|
81
|
+
return phys_val, cursor_position
|
@@ -1,15 +1,16 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
-
import warnings
|
3
2
|
from dataclasses import dataclass
|
3
|
+
from typing import Optional, Tuple, cast
|
4
4
|
|
5
5
|
from ..decodestate import DecodeState
|
6
|
-
from ..
|
6
|
+
from ..encodestate import EncodeState
|
7
|
+
from ..odxtypes import ParameterValue
|
7
8
|
from .parameter import Parameter, ParameterType
|
8
9
|
|
9
10
|
|
10
11
|
@dataclass
|
11
12
|
class ReservedParameter(Parameter):
|
12
|
-
|
13
|
+
bit_length: int
|
13
14
|
|
14
15
|
@property
|
15
16
|
def parameter_type(self) -> ParameterType:
|
@@ -23,44 +24,22 @@ class ReservedParameter(Parameter):
|
|
23
24
|
def is_settable(self) -> bool:
|
24
25
|
return False
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
# this is a bit hacky: the parent class already specifies
|
29
|
-
# bit_length as a function property, and we need to change
|
30
|
-
# this to return the value from the XML here. Since function
|
31
|
-
# attributes cannot be overridden by non-function ones, we
|
32
|
-
# need to take the "bit_length_raw" detour...
|
33
|
-
return self.bit_length_raw
|
34
|
-
|
35
|
-
def get_coded_value(self):
|
36
|
-
return 0
|
27
|
+
def get_static_bit_length(self) -> Optional[int]:
|
28
|
+
return self.bit_length
|
37
29
|
|
38
|
-
def get_coded_value_as_bytes(self, encode_state):
|
30
|
+
def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
|
39
31
|
bit_position_int = self.bit_position if self.bit_position is not None else 0
|
40
|
-
return
|
32
|
+
return (0).to_bytes((self.bit_length + bit_position_int + 7) // 8, "big")
|
41
33
|
|
42
|
-
def decode_from_pdu(self, decode_state: DecodeState):
|
34
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[ParameterValue, int]:
|
43
35
|
byte_position = (
|
44
|
-
self.byte_position
|
45
|
-
|
46
|
-
|
47
|
-
byte_length = (self.bit_length_raw + bit_position_int + 7) // 8
|
48
|
-
val_as_bytes = decode_state.coded_message[byte_position:byte_position + byte_length]
|
49
|
-
next_byte_position = byte_position + byte_length
|
50
|
-
|
51
|
-
# Check that reserved bits are 0
|
52
|
-
expected = sum(
|
53
|
-
2**i for i in range(bit_position_int, bit_position_int + self.bit_length_raw))
|
54
|
-
actual = int.from_bytes(val_as_bytes, "big")
|
36
|
+
self.byte_position if self.byte_position is not None else decode_state.cursor_position)
|
37
|
+
abs_bit_position = byte_position * 8 + (self.bit_position or 0)
|
38
|
+
bit_length = self.bit_length
|
55
39
|
|
56
|
-
#
|
57
|
-
|
58
|
-
|
59
|
-
f"Reserved bits must be Zero! "
|
60
|
-
f"The parameter {self.short_name} expected {self.bit_length} bits to be Zero starting at bit position {bit_position_int} "
|
61
|
-
f"at byte position {byte_position} "
|
62
|
-
f"in coded message {decode_state.coded_message.hex()}.",
|
63
|
-
DecodeError,
|
64
|
-
)
|
40
|
+
# the cursor points to the first byte which has not been fully
|
41
|
+
# consumed
|
42
|
+
cursor_position = (abs_bit_position + bit_length) // 8
|
65
43
|
|
66
|
-
|
44
|
+
# ignore the value of the parameter data
|
45
|
+
return cast(int, None), cursor_position
|
@@ -1,6 +1,10 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
+
from typing import Tuple
|
3
4
|
|
5
|
+
from ..decodestate import DecodeState
|
6
|
+
from ..encodestate import EncodeState
|
7
|
+
from ..odxtypes import ParameterValue
|
4
8
|
from .parameter import ParameterType
|
5
9
|
from .parameterwithdop import ParameterWithDOP
|
6
10
|
|
@@ -21,11 +25,8 @@ class SystemParameter(ParameterWithDOP):
|
|
21
25
|
def is_settable(self) -> bool:
|
22
26
|
raise NotImplementedError("SystemParameter.is_settable is not implemented yet.")
|
23
27
|
|
24
|
-
def
|
28
|
+
def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
|
25
29
|
raise NotImplementedError("Encoding a SystemParameter is not implemented yet.")
|
26
30
|
|
27
|
-
def
|
28
|
-
raise NotImplementedError("Encoding a SystemParameter is not implemented yet.")
|
29
|
-
|
30
|
-
def decode_from_pdu(self, coded_message, default_byte_position=None):
|
31
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[ParameterValue, int]:
|
31
32
|
raise NotImplementedError("Decoding a SystemParameter is not implemented yet.")
|
@@ -1,7 +1,11 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
+
from typing import Tuple
|
3
4
|
|
5
|
+
from ..decodestate import DecodeState
|
6
|
+
from ..encodestate import EncodeState
|
4
7
|
from ..odxlink import OdxLinkRef
|
8
|
+
from ..odxtypes import ParameterValue
|
5
9
|
from .parameter import Parameter, ParameterType
|
6
10
|
|
7
11
|
|
@@ -22,11 +26,8 @@ class TableEntryParameter(Parameter):
|
|
22
26
|
def is_settable(self) -> bool:
|
23
27
|
raise NotImplementedError("TableKeyParameter.is_settable is not implemented yet.")
|
24
28
|
|
25
|
-
def
|
29
|
+
def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
|
26
30
|
raise NotImplementedError("Encoding a TableKeyParameter is not implemented yet.")
|
27
31
|
|
28
|
-
def
|
29
|
-
raise NotImplementedError("Encoding a TableKeyParameter is not implemented yet.")
|
30
|
-
|
31
|
-
def decode_from_pdu(self, coded_message, default_byte_position=None):
|
32
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> Tuple[ParameterValue, int]:
|
32
33
|
raise NotImplementedError("Decoding a TableKeyParameter is not implemented yet.")
|