odxtools 6.6.1__py3-none-any.whl → 6.7.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.
Files changed (81) hide show
  1. odxtools/__init__.py +5 -5
  2. odxtools/basicstructure.py +7 -8
  3. odxtools/cli/_parser_utils.py +15 -0
  4. odxtools/cli/_print_utils.py +4 -3
  5. odxtools/cli/browse.py +19 -14
  6. odxtools/cli/compare.py +24 -16
  7. odxtools/cli/decode.py +2 -1
  8. odxtools/cli/dummy_sub_parser.py +3 -1
  9. odxtools/cli/find.py +2 -1
  10. odxtools/cli/list.py +2 -1
  11. odxtools/cli/main.py +1 -0
  12. odxtools/cli/snoop.py +4 -1
  13. odxtools/comparaminstance.py +7 -5
  14. odxtools/compumethods/compumethod.py +2 -4
  15. odxtools/compumethods/compuscale.py +45 -5
  16. odxtools/compumethods/createanycompumethod.py +28 -36
  17. odxtools/compumethods/limit.py +70 -36
  18. odxtools/compumethods/linearcompumethod.py +68 -59
  19. odxtools/compumethods/tabintpcompumethod.py +19 -8
  20. odxtools/compumethods/texttablecompumethod.py +32 -36
  21. odxtools/dataobjectproperty.py +13 -10
  22. odxtools/decodestate.py +6 -3
  23. odxtools/determinenumberofitems.py +1 -1
  24. odxtools/diagcodedtype.py +5 -4
  25. odxtools/diagdatadictionaryspec.py +108 -83
  26. odxtools/diaglayer.py +75 -35
  27. odxtools/diaglayertype.py +17 -5
  28. odxtools/diagservice.py +1 -1
  29. odxtools/dopbase.py +4 -2
  30. odxtools/dtcdop.py +7 -5
  31. odxtools/dynamiclengthfield.py +6 -5
  32. odxtools/endofpdufield.py +4 -4
  33. odxtools/environmentdatadescription.py +4 -2
  34. odxtools/inputparam.py +1 -1
  35. odxtools/internalconstr.py +14 -5
  36. odxtools/isotp_state_machine.py +14 -6
  37. odxtools/message.py +1 -1
  38. odxtools/multiplexer.py +18 -13
  39. odxtools/multiplexercase.py +27 -5
  40. odxtools/multiplexerswitchkey.py +1 -1
  41. odxtools/nameditemlist.py +7 -6
  42. odxtools/odxlink.py +2 -2
  43. odxtools/odxtypes.py +56 -3
  44. odxtools/outputparam.py +2 -2
  45. odxtools/parameterinfo.py +12 -5
  46. odxtools/parameters/codedconstparameter.py +33 -12
  47. odxtools/parameters/createanyparameter.py +19 -193
  48. odxtools/parameters/dynamicparameter.py +21 -1
  49. odxtools/parameters/lengthkeyparameter.py +28 -4
  50. odxtools/parameters/matchingrequestparameter.py +27 -9
  51. odxtools/parameters/nrcconstparameter.py +34 -11
  52. odxtools/parameters/parameter.py +58 -32
  53. odxtools/parameters/parameterwithdop.py +28 -15
  54. odxtools/parameters/physicalconstantparameter.py +28 -4
  55. odxtools/parameters/reservedparameter.py +32 -18
  56. odxtools/parameters/systemparameter.py +25 -2
  57. odxtools/parameters/tableentryparameter.py +45 -6
  58. odxtools/parameters/tablekeyparameter.py +43 -10
  59. odxtools/parameters/tablestructparameter.py +36 -14
  60. odxtools/parameters/valueparameter.py +24 -2
  61. odxtools/paramlengthinfotype.py +4 -1
  62. odxtools/parentref.py +4 -1
  63. odxtools/scaleconstr.py +11 -5
  64. odxtools/statetransition.py +1 -1
  65. odxtools/staticfield.py +101 -0
  66. odxtools/table.py +2 -1
  67. odxtools/tablerow.py +11 -4
  68. odxtools/templates/macros/printDOP.xml.jinja2 +30 -34
  69. odxtools/templates/macros/printMux.xml.jinja2 +3 -2
  70. odxtools/templates/macros/printParam.xml.jinja2 +9 -9
  71. odxtools/templates/macros/printStaticField.xml.jinja2 +15 -0
  72. odxtools/templates/macros/printVariant.xml.jinja2 +8 -0
  73. odxtools/uds.py +2 -2
  74. odxtools/version.py +2 -2
  75. odxtools/write_pdx_file.py +3 -3
  76. {odxtools-6.6.1.dist-info → odxtools-6.7.1.dist-info}/METADATA +28 -16
  77. {odxtools-6.6.1.dist-info → odxtools-6.7.1.dist-info}/RECORD +81 -79
  78. {odxtools-6.6.1.dist-info → odxtools-6.7.1.dist-info}/WHEEL +1 -1
  79. {odxtools-6.6.1.dist-info → odxtools-6.7.1.dist-info}/LICENSE +0 -0
  80. {odxtools-6.6.1.dist-info → odxtools-6.7.1.dist-info}/entry_points.txt +0 -0
  81. {odxtools-6.6.1.dist-info → odxtools-6.7.1.dist-info}/top_level.txt +0 -0
@@ -1,14 +1,18 @@
1
1
  # SPDX-License-Identifier: MIT
2
- import abc
3
2
  from dataclasses import dataclass
4
3
  from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional
4
+ from xml.etree import ElementTree
5
5
 
6
+ from typing_extensions import final, override
7
+
8
+ from ..createsdgs import create_sdgs_from_et
6
9
  from ..decodestate import DecodeState
7
10
  from ..element import NamedElement
8
11
  from ..encodestate import EncodeState
9
- from ..odxlink import OdxLinkDatabase, OdxLinkId
12
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
10
13
  from ..odxtypes import ParameterValue
11
14
  from ..specialdatagroup import SpecialDataGroup
15
+ from ..utils import dataclass_fields_asdict
12
16
 
13
17
  if TYPE_CHECKING:
14
18
  from ..diaglayer import DiagLayer
@@ -30,12 +34,42 @@ ParameterType = Literal[
30
34
 
31
35
 
32
36
  @dataclass
33
- class Parameter(NamedElement, abc.ABC):
37
+ class Parameter(NamedElement):
38
+ """This class corresponds to POSITIONABLE-PARAM in the ODX
39
+ specification.
40
+
41
+ Be aware that, even though the ODX specification seems to make the
42
+ distinction of "positionable" and "normal" parameters, it does not
43
+ define any non-positionable parameter types.
44
+
45
+ """
34
46
  byte_position: Optional[int]
35
47
  bit_position: Optional[int]
36
48
  semantic: Optional[str]
37
49
  sdgs: List[SpecialDataGroup]
38
50
 
51
+ @staticmethod
52
+ @override
53
+ def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Parameter":
54
+
55
+ kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
56
+
57
+ semantic = et_element.get("SEMANTIC")
58
+ sdgs = create_sdgs_from_et(et_element.find("SDGS"), doc_frags)
59
+
60
+ byte_position_str = et_element.findtext("BYTE-POSITION")
61
+ bit_position_str = et_element.findtext("BIT-POSITION")
62
+
63
+ byte_position = int(byte_position_str) if byte_position_str is not None else None
64
+ bit_position = int(bit_position_str) if bit_position_str is not None else None
65
+
66
+ return Parameter(
67
+ byte_position=byte_position,
68
+ bit_position=bit_position,
69
+ semantic=semantic,
70
+ sdgs=sdgs,
71
+ **kwargs)
72
+
39
73
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
40
74
  result = {}
41
75
 
@@ -53,9 +87,9 @@ class Parameter(NamedElement, abc.ABC):
53
87
  sdg._resolve_snrefs(diag_layer)
54
88
 
55
89
  @property
56
- @abc.abstractmethod
57
90
  def parameter_type(self) -> ParameterType:
58
- pass
91
+ raise NotImplementedError(
92
+ ".parameter_type is not implemented by the concrete parameter class")
59
93
 
60
94
  def get_static_bit_length(self) -> Optional[int]:
61
95
  return None
@@ -70,7 +104,7 @@ class Parameter(NamedElement, abc.ABC):
70
104
  specified.
71
105
 
72
106
  """
73
- raise NotImplementedError
107
+ raise NotImplementedError(".is_required is not implemented by the concrete parameter class")
74
108
 
75
109
  @property
76
110
  def is_settable(self) -> bool:
@@ -81,44 +115,36 @@ class Parameter(NamedElement, abc.ABC):
81
115
  have a default value are settable but not required to be
82
116
  specified.
83
117
  """
84
- raise NotImplementedError
118
+ raise NotImplementedError(".is_settable is not implemented by the concrete parameter class")
85
119
 
86
- @abc.abstractmethod
87
120
  def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
88
121
  """Get the coded value of the parameter given the encode state.
89
122
  Note that this method is called by `encode_into_pdu`.
90
123
  """
91
- pass
124
+ raise NotImplementedError(
125
+ ".get_coded_value_as_bytes() is not implemented by the concrete parameter class")
92
126
 
93
- @abc.abstractmethod
127
+ @final
94
128
  def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
95
- """Decode the parameter value from the coded message.
129
+ orig_cursor = decode_state.cursor_byte_position
130
+ if self.byte_position is not None:
131
+ decode_state.cursor_byte_position = decode_state.origin_byte_position + self.byte_position
96
132
 
97
- If the parameter does have a byte position property, the coded bytes the parameter covers are extracted
98
- at this byte position and the function parameter `default_byte_position` is ignored.
133
+ decode_state.cursor_bit_position = self.bit_position or 0
99
134
 
100
- If the parameter does not have a byte position and a byte position is passed,
101
- the bytes are extracted at the byte position given by the argument `default_byte_position`.
135
+ result = self._decode_positioned_from_pdu(decode_state)
102
136
 
103
- If the parameter does not have a byte position and the argument `default_byte_position` is None,
104
- this function throws a `DecodeError`.
137
+ decode_state.cursor_byte_position = max(decode_state.cursor_byte_position, orig_cursor)
138
+ decode_state.cursor_bit_position = 0
105
139
 
106
- Parameters
107
- ----------
108
- decode_state : DecodeState
109
- The decoding state containing
110
- * the byte message to be decoded
111
- * the parameter values that are already decoded
112
- * the next byte position that is used iff the parameter does not specify a byte position
140
+ return result
113
141
 
114
- Returns
115
- -------
116
- ParameterValuePair | List[ParameterValuePair]
117
- the decoded parameter value (the type is defined by the DOP)
118
- int
119
- the next byte position after the extracted parameter
120
- """
121
- pass
142
+ def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
143
+ """Method which actually decodes the parameter
144
+
145
+ Its location is managed by `Parameter`."""
146
+ raise NotImplementedError(
147
+ "Required method '_decode_positioned_from_pdu()' not implemented by child class")
122
148
 
123
149
  def encode_into_pdu(self, encode_state: EncodeState) -> bytes:
124
150
  """Encode the value of a parameter into a binary blob and return it
@@ -1,6 +1,9 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, Optional
3
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional
4
+ from xml.etree import ElementTree
5
+
6
+ from typing_extensions import override
4
7
 
5
8
  from ..dataobjectproperty import DataObjectProperty
6
9
  from ..decodestate import DecodeState
@@ -8,9 +11,10 @@ from ..dopbase import DopBase
8
11
  from ..dtcdop import DtcDop
9
12
  from ..encodestate import EncodeState
10
13
  from ..exceptions import odxassert, odxrequire
11
- from ..odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
14
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
12
15
  from ..odxtypes import ParameterValue
13
16
  from ..physicaltype import PhysicalType
17
+ from ..utils import dataclass_fields_asdict
14
18
  from .parameter import Parameter
15
19
 
16
20
  if TYPE_CHECKING:
@@ -22,14 +26,30 @@ class ParameterWithDOP(Parameter):
22
26
  dop_ref: Optional[OdxLinkRef]
23
27
  dop_snref: Optional[str]
24
28
 
29
+ @staticmethod
30
+ @override
31
+ def from_et(et_element: ElementTree.Element,
32
+ doc_frags: List[OdxDocFragment]) -> "ParameterWithDOP":
33
+
34
+ kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
35
+
36
+ dop_ref = OdxLinkRef.from_et(et_element.find("DOP-REF"), doc_frags)
37
+ dop_snref = None
38
+ if (dop_snref_elem := et_element.find("DOP-SNREF")) is not None:
39
+ dop_snref = odxrequire(dop_snref_elem.get("SHORT-NAME"))
40
+
41
+ return ParameterWithDOP(dop_ref=dop_ref, dop_snref=dop_snref, **kwargs)
42
+
25
43
  def __post_init__(self) -> None:
26
44
  odxassert(self.dop_snref is not None or self.dop_ref is not None,
27
45
  f"Param {self.short_name} without a DOP-(SN)REF should not exist!")
28
46
  self._dop: Optional[DopBase] = None
29
47
 
48
+ @override
30
49
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
31
50
  return super()._build_odxlinks()
32
51
 
52
+ @override
33
53
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
34
54
  super()._resolve_odxlinks(odxlinks)
35
55
 
@@ -40,6 +60,7 @@ class ParameterWithDOP(Parameter):
40
60
  # (e.g., static and dynamic fields)
41
61
  self._dop = odxlinks.resolve_lenient(self.dop_ref)
42
62
 
63
+ @override
43
64
  def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
44
65
  super()._resolve_snrefs(diag_layer)
45
66
 
@@ -55,6 +76,7 @@ class ParameterWithDOP(Parameter):
55
76
  self._dop, "Specifying a data object property is mandatory but it "
56
77
  "could not be resolved")
57
78
 
79
+ @override
58
80
  def get_static_bit_length(self) -> Optional[int]:
59
81
  if self._dop is not None:
60
82
  return self._dop.get_static_bit_length()
@@ -68,6 +90,7 @@ class ParameterWithDOP(Parameter):
68
90
  else:
69
91
  return None
70
92
 
93
+ @override
71
94
  def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
72
95
  dop = odxrequire(self.dop, "Reference to DOP is not resolved")
73
96
  physical_value = encode_state.parameter_values[self.short_name]
@@ -75,16 +98,6 @@ class ParameterWithDOP(Parameter):
75
98
  return dop.convert_physical_to_bytes(
76
99
  physical_value, encode_state, bit_position=bit_position_int)
77
100
 
78
- def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
79
- orig_cursor = decode_state.cursor_byte_position
80
- if self.byte_position is not None:
81
- decode_state.cursor_byte_position = decode_state.origin_byte_position + self.byte_position
82
-
83
- decode_state.cursor_bit_position = self.bit_position or 0
84
-
85
- # Use DOP to decode
86
- phys_val = self.dop.decode_from_pdu(decode_state)
87
-
88
- decode_state.cursor_byte_position = max(orig_cursor, decode_state.cursor_byte_position)
89
-
90
- return phys_val
101
+ @override
102
+ def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
103
+ return self.dop.decode_from_pdu(decode_state)
@@ -1,13 +1,17 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict
3
+ from typing import TYPE_CHECKING, Any, Dict, List
4
+ from xml.etree import ElementTree
5
+
6
+ from typing_extensions import override
4
7
 
5
8
  from ..dataobjectproperty import DataObjectProperty
6
9
  from ..decodestate import DecodeState
7
10
  from ..encodestate import EncodeState
8
11
  from ..exceptions import DecodeError, odxraise, odxrequire
9
- from ..odxlink import OdxLinkDatabase, OdxLinkId
12
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
10
13
  from ..odxtypes import ParameterValue
14
+ from ..utils import dataclass_fields_asdict
11
15
  from .parameter import ParameterType
12
16
  from .parameterwithdop import ParameterWithDOP
13
17
 
@@ -20,16 +24,32 @@ class PhysicalConstantParameter(ParameterWithDOP):
20
24
 
21
25
  physical_constant_value_raw: str
22
26
 
27
+ @staticmethod
28
+ @override
29
+ def from_et(et_element: ElementTree.Element,
30
+ doc_frags: List[OdxDocFragment]) -> "PhysicalConstantParameter":
31
+
32
+ kwargs = dataclass_fields_asdict(ParameterWithDOP.from_et(et_element, doc_frags))
33
+
34
+ physical_constant_value_raw = odxrequire(et_element.findtext("PHYS-CONSTANT-VALUE"))
35
+
36
+ return PhysicalConstantParameter(
37
+ physical_constant_value_raw=physical_constant_value_raw, **kwargs)
38
+
23
39
  @property
40
+ @override
24
41
  def parameter_type(self) -> ParameterType:
25
42
  return "PHYS-CONST"
26
43
 
44
+ @override
27
45
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
28
46
  return super()._build_odxlinks()
29
47
 
48
+ @override
30
49
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
31
50
  super()._resolve_odxlinks(odxlinks)
32
51
 
52
+ @override
33
53
  def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
34
54
  super()._resolve_snrefs(diag_layer)
35
55
 
@@ -44,13 +64,16 @@ class PhysicalConstantParameter(ParameterWithDOP):
44
64
  return self._physical_constant_value
45
65
 
46
66
  @property
67
+ @override
47
68
  def is_required(self) -> bool:
48
69
  return False
49
70
 
50
71
  @property
72
+ @override
51
73
  def is_settable(self) -> bool:
52
74
  return False
53
75
 
76
+ @override
54
77
  def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
55
78
  dop = odxrequire(self.dop, "Reference to DOP is not resolved")
56
79
  if (self.short_name in encode_state.parameter_values and
@@ -63,9 +86,10 @@ class PhysicalConstantParameter(ParameterWithDOP):
63
86
  return dop.convert_physical_to_bytes(
64
87
  self.physical_constant_value, encode_state, bit_position=bit_position_int)
65
88
 
66
- def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
89
+ @override
90
+ def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
67
91
  # Decode value
68
- phys_val = super().decode_from_pdu(decode_state)
92
+ phys_val = super()._decode_positioned_from_pdu(decode_state)
69
93
 
70
94
  # Check if decoded value matches expected value
71
95
  if phys_val != self.physical_constant_value:
@@ -1,10 +1,16 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Optional, cast
3
+ from typing import List, Optional
4
+ from xml.etree import ElementTree
5
+
6
+ from typing_extensions import override
4
7
 
5
8
  from ..decodestate import DecodeState
6
9
  from ..encodestate import EncodeState
7
- from ..odxtypes import ParameterValue
10
+ from ..exceptions import odxrequire
11
+ from ..odxlink import OdxDocFragment
12
+ from ..odxtypes import DataType, ParameterValue
13
+ from ..utils import dataclass_fields_asdict
8
14
  from .parameter import Parameter, ParameterType
9
15
 
10
16
 
@@ -12,35 +18,43 @@ from .parameter import Parameter, ParameterType
12
18
  class ReservedParameter(Parameter):
13
19
  bit_length: int
14
20
 
21
+ @staticmethod
22
+ @override
23
+ def from_et(et_element: ElementTree.Element,
24
+ doc_frags: List[OdxDocFragment]) -> "ReservedParameter":
25
+
26
+ kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
27
+
28
+ bit_length = int(odxrequire(et_element.findtext("BIT-LENGTH")))
29
+
30
+ return ReservedParameter(bit_length=bit_length, **kwargs)
31
+
15
32
  @property
33
+ @override
16
34
  def parameter_type(self) -> ParameterType:
17
35
  return "RESERVED"
18
36
 
19
37
  @property
38
+ @override
20
39
  def is_required(self) -> bool:
21
40
  return False
22
41
 
23
42
  @property
43
+ @override
24
44
  def is_settable(self) -> bool:
25
45
  return False
26
46
 
47
+ @override
27
48
  def get_static_bit_length(self) -> Optional[int]:
28
49
  return self.bit_length
29
50
 
51
+ @override
30
52
  def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
31
- bit_position_int = self.bit_position if self.bit_position is not None else 0
32
- return (0).to_bytes((self.bit_length + bit_position_int + 7) // 8, "big")
33
-
34
- def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
35
- # move the cursor
36
- orig_cursor = decode_state.cursor_byte_position
37
- if self.byte_position is not None:
38
- decode_state.cursor_byte_position = decode_state.origin_byte_position + self.byte_position
39
-
40
- decode_state.cursor_byte_position += ((self.bit_position or 0) + self.bit_length + 7) // 8
41
-
42
- decode_state.cursor_byte_position = max(orig_cursor, decode_state.cursor_byte_position)
43
- decode_state.cursor_bit_position = 0
44
-
45
- # ignore the value of the parameter data
46
- return cast(int, None)
53
+ return (0).to_bytes(((self.bit_position or 0) + self.bit_length + 7) // 8, "big")
54
+
55
+ @override
56
+ def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
57
+ return decode_state.extract_atomic_value(
58
+ bit_length=self.bit_length,
59
+ base_data_type=DataType.A_UINT32,
60
+ is_highlow_byte_order=False)
@@ -1,9 +1,16 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
+ from typing import List
4
+ from xml.etree import ElementTree
5
+
6
+ from typing_extensions import override
3
7
 
4
8
  from ..decodestate import DecodeState
5
9
  from ..encodestate import EncodeState
10
+ from ..exceptions import odxrequire
11
+ from ..odxlink import OdxDocFragment
6
12
  from ..odxtypes import ParameterValue
13
+ from ..utils import dataclass_fields_asdict
7
14
  from .parameter import ParameterType
8
15
  from .parameterwithdop import ParameterWithDOP
9
16
 
@@ -12,20 +19,36 @@ from .parameterwithdop import ParameterWithDOP
12
19
  class SystemParameter(ParameterWithDOP):
13
20
  sysparam: str
14
21
 
22
+ @staticmethod
23
+ @override
24
+ def from_et(et_element: ElementTree.Element,
25
+ doc_frags: List[OdxDocFragment]) -> "SystemParameter":
26
+
27
+ kwargs = dataclass_fields_asdict(ParameterWithDOP.from_et(et_element, doc_frags))
28
+
29
+ sysparam = odxrequire(et_element.findtext("SYSPARAM"))
30
+
31
+ return SystemParameter(sysparam=sysparam, **kwargs)
32
+
15
33
  @property
34
+ @override
16
35
  def parameter_type(self) -> ParameterType:
17
36
  return "SYSTEM"
18
37
 
19
38
  @property
39
+ @override
20
40
  def is_required(self) -> bool:
21
41
  raise NotImplementedError("SystemParameter.is_required is not implemented yet.")
22
42
 
23
43
  @property
44
+ @override
24
45
  def is_settable(self) -> bool:
25
46
  raise NotImplementedError("SystemParameter.is_settable is not implemented yet.")
26
47
 
48
+ @override
27
49
  def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
28
50
  raise NotImplementedError("Encoding a SystemParameter is not implemented yet.")
29
51
 
30
- def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
31
- raise NotImplementedError("Decoding a SystemParameter is not implemented yet.")
52
+ @override
53
+ def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
54
+ raise NotImplementedError("Decoding SystemParameter is not implemented yet.")
@@ -1,32 +1,71 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
+ from typing import TYPE_CHECKING, List
4
+ from xml.etree import ElementTree
5
+
6
+ from typing_extensions import override
3
7
 
4
8
  from ..decodestate import DecodeState
5
9
  from ..encodestate import EncodeState
6
- from ..odxlink import OdxLinkRef
10
+ from ..exceptions import odxrequire
11
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkRef
7
12
  from ..odxtypes import ParameterValue
13
+ from ..utils import dataclass_fields_asdict
8
14
  from .parameter import Parameter, ParameterType
9
15
 
16
+ if TYPE_CHECKING:
17
+ from ..tablerow import TableRow
18
+
10
19
 
11
20
  @dataclass
12
21
  class TableEntryParameter(Parameter):
13
22
  target: str
14
23
  table_row_ref: OdxLinkRef
15
24
 
25
+ @staticmethod
26
+ @override
27
+ def from_et(et_element: ElementTree.Element,
28
+ doc_frags: List[OdxDocFragment]) -> "TableEntryParameter":
29
+
30
+ kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
31
+
32
+ target = odxrequire(et_element.findtext("TARGET"))
33
+ table_row_ref = odxrequire(OdxLinkRef.from_et(et_element.find("TABLE-ROW-REF"), doc_frags))
34
+
35
+ return TableEntryParameter(target=target, table_row_ref=table_row_ref, **kwargs)
36
+
37
+ @override
38
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
39
+ super()._resolve_odxlinks(odxlinks)
40
+
41
+ if TYPE_CHECKING:
42
+ self._table_row = odxlinks.resolve(self.table_row_ref, TableRow)
43
+ else:
44
+ self._table_row = odxlinks.resolve(self.table_row_ref)
45
+
16
46
  @property
47
+ @override
17
48
  def parameter_type(self) -> ParameterType:
18
49
  return "TABLE-ENTRY"
19
50
 
20
51
  @property
52
+ @override
21
53
  def is_required(self) -> bool:
22
- raise NotImplementedError("TableKeyParameter.is_required is not implemented yet.")
54
+ raise NotImplementedError("TableEntryParameter.is_required is not implemented yet.")
23
55
 
24
56
  @property
57
+ @override
25
58
  def is_settable(self) -> bool:
26
- raise NotImplementedError("TableKeyParameter.is_settable is not implemented yet.")
59
+ raise NotImplementedError("TableEntryParameter.is_settable is not implemented yet.")
27
60
 
61
+ @override
28
62
  def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
29
- raise NotImplementedError("Encoding a TableKeyParameter is not implemented yet.")
63
+ raise NotImplementedError("Encoding a TableEntryParameter is not implemented yet.")
64
+
65
+ @property
66
+ def table_row(self) -> "TableRow":
67
+ return self._table_row
30
68
 
31
- def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
32
- raise NotImplementedError("Decoding a TableKeyParameter is not implemented yet.")
69
+ @override
70
+ def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
71
+ raise NotImplementedError("Decoding a TableEntryParameter is not implemented yet.")
@@ -1,12 +1,16 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, Optional
3
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional
4
+ from xml.etree import ElementTree
5
+
6
+ from typing_extensions import override
4
7
 
5
8
  from ..decodestate import DecodeState
6
9
  from ..encodestate import EncodeState
7
10
  from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
8
- from ..odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
11
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
9
12
  from ..odxtypes import ParameterValue
13
+ from ..utils import dataclass_fields_asdict
10
14
  from .parameter import Parameter, ParameterType
11
15
 
12
16
  if TYPE_CHECKING:
@@ -24,6 +28,33 @@ class TableKeyParameter(Parameter):
24
28
  table_row_snref: Optional[str]
25
29
  table_row_ref: Optional[OdxLinkRef]
26
30
 
31
+ @staticmethod
32
+ @override
33
+ def from_et(et_element: ElementTree.Element,
34
+ doc_frags: List[OdxDocFragment]) -> "TableKeyParameter":
35
+
36
+ kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
37
+
38
+ odx_id = odxrequire(OdxLinkId.from_et(et_element, doc_frags))
39
+
40
+ table_ref = OdxLinkRef.from_et(et_element.find("TABLE-REF"), doc_frags)
41
+ table_snref = None
42
+ if (table_snref_elem := et_element.find("TABLE-SNREF")) is not None:
43
+ table_snref = odxrequire(table_snref_elem.get("SHORT-NAME"))
44
+
45
+ table_row_ref = OdxLinkRef.from_et(et_element.find("TABLE-ROW-REF"), doc_frags)
46
+ table_row_snref = None
47
+ if (table_row_snref_elem := et_element.find("TABLE-ROW-SNREF")) is not None:
48
+ table_row_snref = odxrequire(table_row_snref_elem.get("SHORT-NAME"))
49
+
50
+ return TableKeyParameter(
51
+ odx_id=odx_id,
52
+ table_ref=table_ref,
53
+ table_snref=table_snref,
54
+ table_row_ref=table_row_ref,
55
+ table_row_snref=table_row_snref,
56
+ **kwargs)
57
+
27
58
  def __post_init__(self) -> None:
28
59
  self._table: "Table"
29
60
  self._table_row: Optional["TableRow"] = None
@@ -32,9 +63,11 @@ class TableKeyParameter(Parameter):
32
63
  odxraise("Either a table or a table row must be defined.")
33
64
 
34
65
  @property
66
+ @override
35
67
  def parameter_type(self) -> ParameterType:
36
68
  return "TABLE-KEY"
37
69
 
70
+ @override
38
71
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
39
72
  result = super()._build_odxlinks()
40
73
 
@@ -42,6 +75,7 @@ class TableKeyParameter(Parameter):
42
75
 
43
76
  return result
44
77
 
78
+ @override
45
79
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
46
80
  super()._resolve_odxlinks(odxlinks)
47
81
 
@@ -59,6 +93,7 @@ class TableKeyParameter(Parameter):
59
93
  self._table_row = odxlinks.resolve(self.table_row_ref)
60
94
  self._table = self._table_row.table
61
95
 
96
+ @override
62
97
  def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
63
98
  super()._resolve_snrefs(diag_layer)
64
99
 
@@ -86,15 +121,18 @@ class TableKeyParameter(Parameter):
86
121
  return self._table_row
87
122
 
88
123
  @property
124
+ @override
89
125
  def is_required(self) -> bool:
90
126
  # TABLE-KEY parameters can be implicitly determined from the
91
127
  # corresponding TABLE-STRUCT
92
128
  return False
93
129
 
94
130
  @property
131
+ @override
95
132
  def is_settable(self) -> bool:
96
133
  return True
97
134
 
135
+ @override
98
136
  def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
99
137
  tr_short_name = encode_state.parameter_values.get(self.short_name)
100
138
 
@@ -132,14 +170,12 @@ class TableKeyParameter(Parameter):
132
170
  bit_position = 0 if self.bit_position is None else self.bit_position
133
171
  return key_dop.convert_physical_to_bytes(tr.key, encode_state, bit_position=bit_position)
134
172
 
173
+ @override
135
174
  def encode_into_pdu(self, encode_state: EncodeState) -> bytes:
136
175
  return super().encode_into_pdu(encode_state)
137
176
 
138
- def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
139
- orig_cursor = decode_state.cursor_byte_position
140
- if self.byte_position is not None:
141
- decode_state.cursor_byte_position = decode_state.origin_byte_position + self.byte_position
142
-
177
+ @override
178
+ def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
143
179
  if self.table_row is not None:
144
180
  # the table row to be used is statically specified -> no
145
181
  # need to decode anything!
@@ -147,7 +183,6 @@ class TableKeyParameter(Parameter):
147
183
  else:
148
184
  # Use DOP to decode
149
185
  key_dop = odxrequire(self.table.key_dop)
150
- decode_state.cursor_bit_position = self.bit_position or 0
151
186
  key_dop_val = key_dop.decode_from_pdu(decode_state)
152
187
 
153
188
  table_row_candidates = [x for x in self.table.table_rows if x.key == key_dop_val]
@@ -162,6 +197,4 @@ class TableKeyParameter(Parameter):
162
197
  # update the decode_state's table key
163
198
  decode_state.table_keys[self.short_name] = table_row
164
199
 
165
- decode_state.cursor_byte_position = max(decode_state.cursor_byte_position, orig_cursor)
166
-
167
200
  return phys_val