odxtools 6.7.1__py3-none-any.whl → 7.1.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.
Files changed (60) hide show
  1. odxtools/basicstructure.py +102 -112
  2. odxtools/dataobjectproperty.py +3 -7
  3. odxtools/decodestate.py +1 -13
  4. odxtools/diagcodedtype.py +9 -96
  5. odxtools/diagcomm.py +11 -3
  6. odxtools/diagdatadictionaryspec.py +14 -14
  7. odxtools/diaglayer.py +52 -1
  8. odxtools/diaglayerraw.py +13 -7
  9. odxtools/diagservice.py +12 -16
  10. odxtools/dopbase.py +5 -8
  11. odxtools/dtcdop.py +21 -19
  12. odxtools/dynamicendmarkerfield.py +119 -0
  13. odxtools/dynamiclengthfield.py +39 -29
  14. odxtools/dynenddopref.py +38 -0
  15. odxtools/encodestate.py +188 -23
  16. odxtools/endofpdufield.py +33 -18
  17. odxtools/environmentdata.py +8 -1
  18. odxtools/environmentdatadescription.py +21 -15
  19. odxtools/field.py +4 -3
  20. odxtools/leadinglengthinfotype.py +25 -12
  21. odxtools/matchingparameter.py +2 -2
  22. odxtools/minmaxlengthtype.py +36 -26
  23. odxtools/multiplexer.py +42 -23
  24. odxtools/multiplexercase.py +3 -3
  25. odxtools/multiplexerdefaultcase.py +7 -3
  26. odxtools/nameditemlist.py +14 -0
  27. odxtools/odxlink.py +38 -4
  28. odxtools/odxtypes.py +20 -2
  29. odxtools/parameterinfo.py +126 -40
  30. odxtools/parameters/codedconstparameter.py +17 -13
  31. odxtools/parameters/dynamicparameter.py +5 -4
  32. odxtools/parameters/lengthkeyparameter.py +66 -17
  33. odxtools/parameters/matchingrequestparameter.py +23 -11
  34. odxtools/parameters/nrcconstparameter.py +42 -22
  35. odxtools/parameters/parameter.py +35 -42
  36. odxtools/parameters/parameterwithdop.py +15 -22
  37. odxtools/parameters/physicalconstantparameter.py +16 -16
  38. odxtools/parameters/reservedparameter.py +5 -2
  39. odxtools/parameters/systemparameter.py +3 -2
  40. odxtools/parameters/tableentryparameter.py +3 -2
  41. odxtools/parameters/tablekeyparameter.py +88 -39
  42. odxtools/parameters/tablestructparameter.py +45 -44
  43. odxtools/parameters/valueparameter.py +16 -17
  44. odxtools/paramlengthinfotype.py +30 -22
  45. odxtools/request.py +9 -0
  46. odxtools/response.py +5 -13
  47. odxtools/standardlengthtype.py +51 -13
  48. odxtools/statechart.py +5 -9
  49. odxtools/statetransition.py +3 -8
  50. odxtools/staticfield.py +30 -20
  51. odxtools/tablerow.py +5 -3
  52. odxtools/templates/macros/printDynamicEndmarkerField.xml.jinja2 +16 -0
  53. odxtools/templates/macros/printVariant.xml.jinja2 +8 -0
  54. odxtools/version.py +2 -2
  55. {odxtools-6.7.1.dist-info → odxtools-7.1.0.dist-info}/METADATA +1 -1
  56. {odxtools-6.7.1.dist-info → odxtools-7.1.0.dist-info}/RECORD +60 -57
  57. {odxtools-6.7.1.dist-info → odxtools-7.1.0.dist-info}/LICENSE +0 -0
  58. {odxtools-6.7.1.dist-info → odxtools-7.1.0.dist-info}/WHEEL +0 -0
  59. {odxtools-6.7.1.dist-info → odxtools-7.1.0.dist-info}/entry_points.txt +0 -0
  60. {odxtools-6.7.1.dist-info → odxtools-7.1.0.dist-info}/top_level.txt +0 -0
@@ -1,17 +1,17 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List
3
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
- from typing_extensions import override
6
+ from typing_extensions import final, override
7
7
 
8
8
  from ..decodestate import DecodeState
9
9
  from ..encodestate import EncodeState
10
- from ..exceptions import odxraise, odxrequire
10
+ from ..exceptions import EncodeError, odxraise, odxrequire
11
11
  from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
12
12
  from ..odxtypes import ParameterValue
13
13
  from ..utils import dataclass_fields_asdict
14
- from .parameter import ParameterType
14
+ from .parameter import Parameter, ParameterType
15
15
  from .parameterwithdop import ParameterWithDOP
16
16
 
17
17
  if TYPE_CHECKING:
@@ -60,8 +60,9 @@ class LengthKeyParameter(ParameterWithDOP):
60
60
  super()._resolve_odxlinks(odxlinks)
61
61
 
62
62
  @override
63
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
64
- super()._resolve_snrefs(diag_layer)
63
+ def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *,
64
+ param_list: List[Parameter]) -> None:
65
+ super()._parameter_resolve_snrefs(diag_layer, param_list=param_list)
65
66
 
66
67
  @property
67
68
  @override
@@ -77,17 +78,65 @@ class LengthKeyParameter(ParameterWithDOP):
77
78
  return True
78
79
 
79
80
  @override
80
- def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
81
- physical_value = encode_state.parameter_values.get(self.short_name, 0)
82
-
83
- bit_pos = self.bit_position or 0
84
- dop = odxrequire(super().dop,
85
- f"A DOP is required for length key parameter {self.short_name}")
86
- return dop.convert_physical_to_bytes(physical_value, encode_state, bit_position=bit_pos)
87
-
88
- @override
89
- def encode_into_pdu(self, encode_state: EncodeState) -> bytes:
90
- return super().encode_into_pdu(encode_state)
81
+ @final
82
+ def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
83
+ encode_state: EncodeState) -> None:
84
+ # if you get this exception, you ought to use
85
+ # `.encode_placeholder_into_pdu()` followed by (after the
86
+ # value of the length key has been determined)
87
+ # `.encode_value_into_pdu()`.
88
+ raise RuntimeError("_encode_positioned_into_pdu() cannot be called for length keys.")
89
+
90
+ def encode_placeholder_into_pdu(self, physical_value: Optional[ParameterValue],
91
+ encode_state: EncodeState) -> None:
92
+
93
+ if physical_value is not None:
94
+ if not self.dop.is_valid_physical_value(physical_value):
95
+ odxraise(f"Invalid explicitly specified physical value '{physical_value!r}' "
96
+ f"for length key '{self.short_name}'.")
97
+
98
+ lkv = encode_state.length_keys.get(self.short_name)
99
+ if lkv is not None and lkv != physical_value:
100
+ odxraise(f"Got conflicting values for length key {self.short_name}: "
101
+ f"{lkv} and {physical_value!r}")
102
+
103
+ if not isinstance(physical_value, int):
104
+ odxraise(
105
+ f"Value of length key {self.short_name} is of type {type(physical_value).__name__} "
106
+ f"instead of int")
107
+
108
+ encode_state.length_keys[self.short_name] = physical_value
109
+
110
+ orig_cursor = encode_state.cursor_byte_position
111
+ pos = encode_state.cursor_byte_position
112
+ if self.byte_position is not None:
113
+ pos = encode_state.origin_byte_position + self.byte_position
114
+ encode_state.key_pos[self.short_name] = pos
115
+ encode_state.cursor_byte_position = pos
116
+ encode_state.cursor_bit_position = self.bit_position or 0
117
+
118
+ # emplace a value of zero into the encode state, but pretend the bits not to be used
119
+ n = odxrequire(self.dop.get_static_bit_length()) + encode_state.cursor_bit_position
120
+ tmp_val = b'\x00' * ((n + 7) // 8)
121
+ encode_state.emplace_bytes(tmp_val, obj_used_mask=tmp_val)
122
+
123
+ encode_state.cursor_byte_position = max(encode_state.cursor_byte_position, orig_cursor)
124
+ encode_state.cursor_bit_position = 0
125
+
126
+ def encode_value_into_pdu(self, encode_state: EncodeState) -> None:
127
+
128
+ if self.short_name not in encode_state.length_keys:
129
+ odxraise(
130
+ f"Length key {self.short_name} has not been defined before "
131
+ f"it is required.", EncodeError)
132
+ return
133
+ else:
134
+ physical_value = encode_state.length_keys[self.short_name]
135
+
136
+ encode_state.cursor_byte_position = encode_state.key_pos[self.short_name]
137
+ encode_state.cursor_bit_position = self.bit_position or 0
138
+
139
+ self.dop.encode_into_pdu(encode_state=encode_state, physical_value=physical_value)
91
140
 
92
141
  @override
93
142
  def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
@@ -7,7 +7,7 @@ from typing_extensions import override
7
7
 
8
8
  from ..decodestate import DecodeState
9
9
  from ..encodestate import EncodeState
10
- from ..exceptions import EncodeError, odxrequire
10
+ from ..exceptions import EncodeError, odxraise, odxrequire
11
11
  from ..odxlink import OdxDocFragment
12
12
  from ..odxtypes import DataType, ParameterValue
13
13
  from ..utils import dataclass_fields_asdict
@@ -52,19 +52,31 @@ class MatchingRequestParameter(Parameter):
52
52
  return False
53
53
 
54
54
  @override
55
- def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
56
- if not encode_state.triggering_request:
57
- raise EncodeError(f"Parameter '{self.short_name}' is of matching request type,"
58
- " but no original request has been specified.")
59
- return encode_state.triggering_request[self
60
- .request_byte_position:self.request_byte_position +
61
- self.byte_length]
55
+ def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
56
+ encode_state: EncodeState) -> None:
57
+ if encode_state.triggering_request is None:
58
+ odxraise(
59
+ f"Parameter '{self.short_name}' is of matching request type,"
60
+ f" but no original request has been specified.", EncodeError)
61
+ return
62
+
63
+ rq_pos = self.request_byte_position
64
+ rq_len = self.byte_length
65
+
66
+ if len(encode_state.triggering_request) < rq_pos + rq_len:
67
+ odxraise(
68
+ f"Specified triggering request 0x{encode_state.triggering_request.hex()} "
69
+ f"is not long enough to encode matching request parameter "
70
+ f"'{self.short_name}': Have {len(encode_state.triggering_request)} "
71
+ f"bytes, need at least {rq_pos + rq_len} bytes", EncodeError)
72
+ return
73
+
74
+ encode_state.emplace_bytes(encode_state.triggering_request[rq_pos:rq_pos + rq_len],
75
+ self.short_name)
62
76
 
63
77
  @override
64
78
  def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
65
- result = decode_state.extract_atomic_value(
79
+ return decode_state.extract_atomic_value(
66
80
  bit_length=self.byte_length * 8,
67
81
  base_data_type=DataType.A_UINT32,
68
82
  is_highlow_byte_order=False)
69
-
70
- return result
@@ -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, List, Optional
4
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast
5
5
  from xml.etree import ElementTree
6
6
 
7
7
  from typing_extensions import override
@@ -10,9 +10,9 @@ from ..createanydiagcodedtype import create_any_diag_coded_type_from_et
10
10
  from ..decodestate import DecodeState
11
11
  from ..diagcodedtype import DiagCodedType
12
12
  from ..encodestate import EncodeState
13
- from ..exceptions import DecodeError, EncodeError, odxrequire
13
+ from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
14
14
  from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
15
- from ..odxtypes import AtomicOdxType, DataType
15
+ from ..odxtypes import AtomicOdxType, DataType, ParameterValue
16
16
  from ..utils import dataclass_fields_asdict
17
17
  from .parameter import Parameter, ParameterType
18
18
 
@@ -22,13 +22,19 @@ if TYPE_CHECKING:
22
22
 
23
23
  @dataclass
24
24
  class NrcConstParameter(Parameter):
25
- """A param of type NRC-CONST defines a set of values to be matched.
25
+ """A param of type NRC-CONST defines a set of values to be matched for a negative response to apply.
26
26
 
27
- An NRC-CONST can only be used in a negative response.
28
- Its encoding behaviour is similar to a VALUE parameter with a TEXTTABLE.
29
- However, an NRC-CONST is used for matching a response (similar to a CODED-CONST).
27
+ The behaviour of NRC-CONST parameters is similar to CODED-CONST
28
+ parameters in that they allow to specify which coding objects
29
+ apply to a binary string, but in contrast to CODED-CONST
30
+ parameters they allow to specify multiple values. Thus, the value
31
+ of a CODED-CONST parameter is usually set using an overlapping
32
+ VALUE parameter. Since NRC-CONST parameters can only be specified
33
+ for negative responses, they can thus be regarded as a multiplexer
34
+ mechanism that is specific to negative responses.
30
35
 
31
36
  See ASAM MCD-2 D (ODX), p. 77-79.
37
+
32
38
  """
33
39
 
34
40
  diag_coded_type: DiagCodedType
@@ -69,8 +75,9 @@ class NrcConstParameter(Parameter):
69
75
  super()._resolve_odxlinks(odxlinks)
70
76
 
71
77
  @override
72
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
73
- super()._resolve_snrefs(diag_layer)
78
+ def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *,
79
+ param_list: List[Parameter]) -> None:
80
+ super()._parameter_resolve_snrefs(diag_layer, param_list=param_list)
74
81
 
75
82
  @override
76
83
  def get_static_bit_length(self) -> Optional[int]:
@@ -91,21 +98,34 @@ class NrcConstParameter(Parameter):
91
98
  return False
92
99
 
93
100
  @override
94
- def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
95
- if self.short_name in encode_state.parameter_values:
96
- if encode_state.parameter_values[self.short_name] not in self.coded_values:
97
- raise EncodeError(f"The parameter '{self.short_name}' must have"
98
- f" one of the constant values {self.coded_values}")
101
+ def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
102
+ encode_state: EncodeState) -> None:
103
+ coded_value: ParameterValue
104
+ if physical_value is not None:
105
+ if physical_value not in self.coded_values:
106
+ odxraise(
107
+ f"The value of parameter '{self.short_name}' must "
108
+ f" be one of {self.coded_values} (is: {physical_value!r})", EncodeError)
109
+ coded_value = self.coded_values[0]
99
110
  else:
100
- coded_value = encode_state.parameter_values[self.short_name]
111
+ coded_value = physical_value
101
112
  else:
102
- # If the user does not select one, just select any.
103
- # I think it does not matter ...
104
- coded_value = self.coded_values[0]
105
-
106
- bit_position_int = self.bit_position if self.bit_position is not None else 0
107
- return self.diag_coded_type.convert_internal_to_bytes(
108
- coded_value, encode_state, bit_position=bit_position_int)
113
+ # If the user did not select a value, the value of the
114
+ # this parameter is set by another parameter which
115
+ # overlaps with it. We thus just move the cursor.
116
+ bit_pos = encode_state.cursor_bit_position
117
+ bit_len = self.diag_coded_type.get_static_bit_length()
118
+
119
+ if bit_len is None:
120
+ odxraise("The diag coded type of NRC-CONST parameters must "
121
+ "exhibit a static size")
122
+ return
123
+
124
+ encode_state.cursor_byte_position += (bit_pos + bit_len + 7) // 8
125
+ encode_state.cursor_bit_position = 0
126
+ return
127
+
128
+ self.diag_coded_type.encode_into_pdu(cast(AtomicOdxType, coded_value), encode_state)
109
129
 
110
130
  @override
111
131
  def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> AtomicOdxType:
@@ -82,7 +82,13 @@ class Parameter(NamedElement):
82
82
  for sdg in self.sdgs:
83
83
  sdg._resolve_odxlinks(odxlinks)
84
84
 
85
+ @final
85
86
  def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
87
+ raise RuntimeError("Calling _resolve_snrefs() is not allowed for parameters. "
88
+ "Use _parameter_resolve_snrefs() instead.")
89
+
90
+ def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *,
91
+ param_list: List["Parameter"]) -> None:
86
92
  for sdg in self.sdgs:
87
93
  sdg._resolve_snrefs(diag_layer)
88
94
 
@@ -117,12 +123,35 @@ class Parameter(NamedElement):
117
123
  """
118
124
  raise NotImplementedError(".is_settable is not implemented by the concrete parameter class")
119
125
 
120
- def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
121
- """Get the coded value of the parameter given the encode state.
122
- Note that this method is called by `encode_into_pdu`.
126
+ @final
127
+ def encode_into_pdu(self, physical_value: Optional[ParameterValue],
128
+ encode_state: EncodeState) -> None:
129
+ """Convert a physical value into its encoded form and place it into the PDU
130
+
131
+ Also, adapt the `encode_state` so that it points to where the next
132
+ parameter is located (if the parameter does not explicitly specify a
133
+ position)
123
134
  """
135
+
136
+ orig_cursor = encode_state.cursor_byte_position
137
+ if self.byte_position is not None:
138
+ encode_state.cursor_byte_position = encode_state.origin_byte_position + self.byte_position
139
+
140
+ encode_state.cursor_bit_position = self.bit_position or 0
141
+
142
+ self._encode_positioned_into_pdu(physical_value, encode_state)
143
+
144
+ encode_state.cursor_byte_position = max(encode_state.cursor_byte_position, orig_cursor)
145
+ encode_state.cursor_bit_position = 0
146
+
147
+ def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
148
+ encode_state: EncodeState) -> None:
149
+ """Method which actually encodes the parameter
150
+
151
+ Its location is managed by `Parameter`."""
124
152
  raise NotImplementedError(
125
- ".get_coded_value_as_bytes() is not implemented by the concrete parameter class")
153
+ f"Required method '_encode_positioned_into_pdu()' not implemented by "
154
+ f"child class {type(self).__name__}")
126
155
 
127
156
  @final
128
157
  def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
@@ -144,41 +173,5 @@ class Parameter(NamedElement):
144
173
 
145
174
  Its location is managed by `Parameter`."""
146
175
  raise NotImplementedError(
147
- "Required method '_decode_positioned_from_pdu()' not implemented by child class")
148
-
149
- def encode_into_pdu(self, encode_state: EncodeState) -> bytes:
150
- """Encode the value of a parameter into a binary blob and return it
151
-
152
- If the byte position of the parameter is not defined,
153
- the byte code is appended to the blob.
154
-
155
- Technical note for subclasses: The default implementation
156
- tries to compute the coded value via
157
- `self.get_coded_value_as_bytes(encoded_state)` and inserts it
158
- into the PDU. Thus it usually suffices to overwrite
159
- `get_coded_value_as_bytes()` instead of `encode_into_pdu()`.
160
-
161
- Parameters:
162
- ----------
163
- encode_state: EncodeState, i.e. a named tuple with attributes
164
- * coded_message: bytes, the message encoded so far
165
- * parameter_values: List[ParameterValuePairs]
166
- * triggering_coded_request: bytes
167
-
168
- Returns:
169
- -------
170
- bytes
171
- the message's blob after adding the encoded parameter into it
172
-
173
- """
174
- msg_blob = encode_state.coded_message
175
- param_blob = self.get_coded_value_as_bytes(encode_state)
176
-
177
- if self.byte_position is not None:
178
- byte_position = self.byte_position
179
- else:
180
- byte_position = len(msg_blob)
181
-
182
- encode_state.emplace_atomic_value(param_blob, self.short_name, byte_position)
183
-
184
- return encode_state.coded_message
176
+ f"Required method '_decode_positioned_from_pdu()' not implemented by "
177
+ f"child class {type(self).__name__}")
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
3
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from typing_extensions import override
@@ -11,8 +11,8 @@ from ..dopbase import DopBase
11
11
  from ..dtcdop import DtcDop
12
12
  from ..encodestate import EncodeState
13
13
  from ..exceptions import odxassert, odxrequire
14
- from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
15
- from ..odxtypes import ParameterValue
14
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
15
+ from ..odxtypes import AtomicOdxType, ParameterValue
16
16
  from ..physicaltype import PhysicalType
17
17
  from ..utils import dataclass_fields_asdict
18
18
  from .parameter import Parameter
@@ -43,7 +43,7 @@ class ParameterWithDOP(Parameter):
43
43
  def __post_init__(self) -> None:
44
44
  odxassert(self.dop_snref is not None or self.dop_ref is not None,
45
45
  f"Param {self.short_name} without a DOP-(SN)REF should not exist!")
46
- self._dop: Optional[DopBase] = None
46
+ self._dop: DopBase
47
47
 
48
48
  @override
49
49
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
@@ -55,26 +55,22 @@ class ParameterWithDOP(Parameter):
55
55
 
56
56
  if self.dop_ref is not None:
57
57
  odxassert(self.dop_snref is None)
58
- # TODO: do not do lenient resolves here. The problem is
59
- # that currently not all kinds of DOPs are internalized
60
- # (e.g., static and dynamic fields)
61
- self._dop = odxlinks.resolve_lenient(self.dop_ref)
58
+ self._dop = odxlinks.resolve(self.dop_ref)
62
59
 
63
60
  @override
64
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
65
- super()._resolve_snrefs(diag_layer)
61
+ def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *,
62
+ param_list: List[Parameter]) -> None:
63
+ super()._parameter_resolve_snrefs(diag_layer, param_list=param_list)
66
64
 
67
65
  if self.dop_snref:
68
- ddds = diag_layer.diag_data_dictionary_spec
69
- self._dop = odxrequire(ddds.all_data_object_properties.get(self.dop_snref))
66
+ all_dops = diag_layer.diag_data_dictionary_spec.all_data_object_properties
67
+ self._dop = resolve_snref(self.dop_snref, all_dops, DopBase)
70
68
 
71
69
  @property
72
70
  def dop(self) -> DopBase:
73
- """may be a DataObjectProperty, a Structure or None"""
71
+ """This is usually a DataObjectProperty or a Structure object"""
74
72
 
75
- return odxrequire(
76
- self._dop, "Specifying a data object property is mandatory but it "
77
- "could not be resolved")
73
+ return self._dop
78
74
 
79
75
  @override
80
76
  def get_static_bit_length(self) -> Optional[int]:
@@ -91,12 +87,9 @@ class ParameterWithDOP(Parameter):
91
87
  return None
92
88
 
93
89
  @override
94
- def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
95
- dop = odxrequire(self.dop, "Reference to DOP is not resolved")
96
- physical_value = encode_state.parameter_values[self.short_name]
97
- bit_position_int = self.bit_position if self.bit_position is not None else 0
98
- return dop.convert_physical_to_bytes(
99
- physical_value, encode_state, bit_position=bit_position_int)
90
+ def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
91
+ encode_state: EncodeState) -> None:
92
+ self.dop.encode_into_pdu(cast(AtomicOdxType, physical_value), encode_state)
100
93
 
101
94
  @override
102
95
  def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List
3
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from typing_extensions import override
@@ -8,11 +8,11 @@ from typing_extensions import override
8
8
  from ..dataobjectproperty import DataObjectProperty
9
9
  from ..decodestate import DecodeState
10
10
  from ..encodestate import EncodeState
11
- from ..exceptions import DecodeError, odxraise, odxrequire
11
+ from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
12
12
  from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
13
13
  from ..odxtypes import ParameterValue
14
14
  from ..utils import dataclass_fields_asdict
15
- from .parameter import ParameterType
15
+ from .parameter import Parameter, ParameterType
16
16
  from .parameterwithdop import ParameterWithDOP
17
17
 
18
18
  if TYPE_CHECKING:
@@ -50,8 +50,9 @@ class PhysicalConstantParameter(ParameterWithDOP):
50
50
  super()._resolve_odxlinks(odxlinks)
51
51
 
52
52
  @override
53
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
54
- super()._resolve_snrefs(diag_layer)
53
+ def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *,
54
+ param_list: List[Parameter]) -> None:
55
+ super()._parameter_resolve_snrefs(diag_layer, param_list=param_list)
55
56
 
56
57
  dop = odxrequire(self.dop)
57
58
  if not isinstance(dop, DataObjectProperty):
@@ -74,17 +75,15 @@ class PhysicalConstantParameter(ParameterWithDOP):
74
75
  return False
75
76
 
76
77
  @override
77
- def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
78
- dop = odxrequire(self.dop, "Reference to DOP is not resolved")
79
- if (self.short_name in encode_state.parameter_values and
80
- encode_state.parameter_values[self.short_name] != self.physical_constant_value):
81
- raise TypeError(
82
- f"The parameter '{self.short_name}' is constant {self.physical_constant_value!r}"
83
- f" and thus can not be changed.")
84
-
85
- bit_position_int = self.bit_position if self.bit_position is not None else 0
86
- return dop.convert_physical_to_bytes(
87
- self.physical_constant_value, encode_state, bit_position=bit_position_int)
78
+ def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
79
+ encode_state: EncodeState) -> None:
80
+ if physical_value is not None and physical_value != self.physical_constant_value:
81
+ odxraise(
82
+ f"Value for constant parameter `{self.short_name}` name can "
83
+ f"only be specified as {self.physical_constant_value!r} (is: {physical_value!r})",
84
+ EncodeError)
85
+
86
+ self.dop.encode_into_pdu(self.physical_constant_value, encode_state)
88
87
 
89
88
  @override
90
89
  def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
@@ -99,4 +98,5 @@ class PhysicalConstantParameter(ParameterWithDOP):
99
98
  f"{self.physical_constant_value!r} but got {phys_val!r} "
100
99
  f"at byte position {decode_state.cursor_byte_position} "
101
100
  f"in coded message {decode_state.coded_message.hex()}.", DecodeError)
101
+
102
102
  return phys_val
@@ -49,8 +49,11 @@ class ReservedParameter(Parameter):
49
49
  return self.bit_length
50
50
 
51
51
  @override
52
- def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
53
- return (0).to_bytes(((self.bit_position or 0) + self.bit_length + 7) // 8, "big")
52
+ def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
53
+ encode_state: EncodeState) -> None:
54
+ raw_data = (0).to_bytes((encode_state.cursor_bit_position + self.bit_length + 7) // 8,
55
+ "big")
56
+ encode_state.emplace_bytes(raw_data, self.short_name)
54
57
 
55
58
  @override
56
59
  def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import List
3
+ from typing import List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from typing_extensions import override
@@ -46,7 +46,8 @@ class SystemParameter(ParameterWithDOP):
46
46
  raise NotImplementedError("SystemParameter.is_settable is not implemented yet.")
47
47
 
48
48
  @override
49
- def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
49
+ def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
50
+ encode_state: EncodeState) -> None:
50
51
  raise NotImplementedError("Encoding a SystemParameter is not implemented yet.")
51
52
 
52
53
  @override
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, List
3
+ from typing import TYPE_CHECKING, List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from typing_extensions import override
@@ -59,7 +59,8 @@ class TableEntryParameter(Parameter):
59
59
  raise NotImplementedError("TableEntryParameter.is_settable is not implemented yet.")
60
60
 
61
61
  @override
62
- def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
62
+ def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
63
+ encode_state: EncodeState) -> None:
63
64
  raise NotImplementedError("Encoding a TableEntryParameter is not implemented yet.")
64
65
 
65
66
  @property