odxtools 6.6.0__py3-none-any.whl → 6.7.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 (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 +27 -35
  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 +14 -8
  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 +30 -10
  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 +27 -3
  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.0.dist-info → odxtools-6.7.0.dist-info}/METADATA +28 -16
  77. {odxtools-6.6.0.dist-info → odxtools-6.7.0.dist-info}/RECORD +81 -79
  78. {odxtools-6.6.0.dist-info → odxtools-6.7.0.dist-info}/WHEEL +1 -1
  79. {odxtools-6.6.0.dist-info → odxtools-6.7.0.dist-info}/LICENSE +0 -0
  80. {odxtools-6.6.0.dist-info → odxtools-6.7.0.dist-info}/entry_points.txt +0 -0
  81. {odxtools-6.6.0.dist-info → odxtools-6.7.0.dist-info}/top_level.txt +0 -0
@@ -2,13 +2,18 @@
2
2
  import warnings
3
3
  from dataclasses import dataclass
4
4
  from typing import TYPE_CHECKING, Any, Dict, List, Optional
5
+ from xml.etree import ElementTree
5
6
 
7
+ from typing_extensions import override
8
+
9
+ from ..createanydiagcodedtype import create_any_diag_coded_type_from_et
6
10
  from ..decodestate import DecodeState
7
11
  from ..diagcodedtype import DiagCodedType
8
12
  from ..encodestate import EncodeState
9
- from ..exceptions import DecodeError, EncodeError
10
- from ..odxlink import OdxLinkDatabase, OdxLinkId
13
+ from ..exceptions import DecodeError, EncodeError, odxrequire
14
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
11
15
  from ..odxtypes import AtomicOdxType, DataType
16
+ from ..utils import dataclass_fields_asdict
12
17
  from .parameter import Parameter, ParameterType
13
18
 
14
19
  if TYPE_CHECKING:
@@ -29,10 +34,29 @@ class NrcConstParameter(Parameter):
29
34
  diag_coded_type: DiagCodedType
30
35
  coded_values: List[AtomicOdxType]
31
36
 
37
+ @staticmethod
38
+ @override
39
+ def from_et(et_element: ElementTree.Element,
40
+ doc_frags: List[OdxDocFragment]) -> "NrcConstParameter":
41
+
42
+ kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
43
+
44
+ dct_elem = odxrequire(et_element.find("DIAG-CODED-TYPE"))
45
+ diag_coded_type = create_any_diag_coded_type_from_et(dct_elem, doc_frags)
46
+ coded_values = [
47
+ diag_coded_type.base_data_type.from_string(odxrequire(val.text))
48
+ for val in et_element.iterfind("CODED-VALUES/CODED-VALUE")
49
+ ]
50
+
51
+ return NrcConstParameter(
52
+ diag_coded_type=diag_coded_type, coded_values=coded_values, **kwargs)
53
+
32
54
  @property
55
+ @override
33
56
  def parameter_type(self) -> ParameterType:
34
57
  return "NRC-CONST"
35
58
 
59
+ @override
36
60
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
37
61
  result = super()._build_odxlinks()
38
62
 
@@ -40,12 +64,15 @@ class NrcConstParameter(Parameter):
40
64
 
41
65
  return result
42
66
 
67
+ @override
43
68
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
44
69
  super()._resolve_odxlinks(odxlinks)
45
70
 
71
+ @override
46
72
  def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
47
73
  super()._resolve_snrefs(diag_layer)
48
74
 
75
+ @override
49
76
  def get_static_bit_length(self) -> Optional[int]:
50
77
  return self.diag_coded_type.get_static_bit_length()
51
78
 
@@ -54,13 +81,16 @@ class NrcConstParameter(Parameter):
54
81
  return self.diag_coded_type.base_data_type
55
82
 
56
83
  @property
84
+ @override
57
85
  def is_required(self) -> bool:
58
86
  return False
59
87
 
60
88
  @property
89
+ @override
61
90
  def is_settable(self) -> bool:
62
91
  return False
63
92
 
93
+ @override
64
94
  def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
65
95
  if self.short_name in encode_state.parameter_values:
66
96
  if encode_state.parameter_values[self.short_name] not in self.coded_values:
@@ -77,14 +107,9 @@ class NrcConstParameter(Parameter):
77
107
  return self.diag_coded_type.convert_internal_to_bytes(
78
108
  coded_value, encode_state, bit_position=bit_position_int)
79
109
 
80
- def decode_from_pdu(self, decode_state: DecodeState) -> AtomicOdxType:
81
- orig_cursor = decode_state.cursor_byte_position
82
- if self.byte_position is not None:
83
- # Update cursor position
84
- decode_state.cursor_byte_position = decode_state.origin_byte_position + self.byte_position
85
-
110
+ @override
111
+ def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> AtomicOdxType:
86
112
  # Extract coded values
87
- decode_state.cursor_bit_position = self.bit_position or 0
88
113
  coded_value = self.diag_coded_type.decode_from_pdu(decode_state)
89
114
 
90
115
  # Check if the coded value in the message is correct.
@@ -99,8 +124,6 @@ class NrcConstParameter(Parameter):
99
124
  stacklevel=1,
100
125
  )
101
126
 
102
- decode_state.cursor_byte_position = max(decode_state.cursor_byte_position, orig_cursor)
103
-
104
127
  return coded_value
105
128
 
106
129
  def get_description_of_valid_values(self) -> str:
@@ -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,14 +1,17 @@
1
1
  # SPDX-License-Identifier: MIT
2
- import warnings
3
2
  from dataclasses import dataclass
4
- 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
5
7
 
6
8
  from ..dataobjectproperty import DataObjectProperty
7
9
  from ..decodestate import DecodeState
8
10
  from ..encodestate import EncodeState
9
11
  from ..exceptions import DecodeError, odxraise, odxrequire
10
- from ..odxlink import OdxLinkDatabase, OdxLinkId
12
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
11
13
  from ..odxtypes import ParameterValue
14
+ from ..utils import dataclass_fields_asdict
12
15
  from .parameter import ParameterType
13
16
  from .parameterwithdop import ParameterWithDOP
14
17
 
@@ -21,16 +24,32 @@ class PhysicalConstantParameter(ParameterWithDOP):
21
24
 
22
25
  physical_constant_value_raw: str
23
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
+
24
39
  @property
40
+ @override
25
41
  def parameter_type(self) -> ParameterType:
26
42
  return "PHYS-CONST"
27
43
 
44
+ @override
28
45
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
29
46
  return super()._build_odxlinks()
30
47
 
48
+ @override
31
49
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
32
50
  super()._resolve_odxlinks(odxlinks)
33
51
 
52
+ @override
34
53
  def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
35
54
  super()._resolve_snrefs(diag_layer)
36
55
 
@@ -45,13 +64,16 @@ class PhysicalConstantParameter(ParameterWithDOP):
45
64
  return self._physical_constant_value
46
65
 
47
66
  @property
67
+ @override
48
68
  def is_required(self) -> bool:
49
69
  return False
50
70
 
51
71
  @property
72
+ @override
52
73
  def is_settable(self) -> bool:
53
74
  return False
54
75
 
76
+ @override
55
77
  def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
56
78
  dop = odxrequire(self.dop, "Reference to DOP is not resolved")
57
79
  if (self.short_name in encode_state.parameter_values and
@@ -64,19 +86,17 @@ class PhysicalConstantParameter(ParameterWithDOP):
64
86
  return dop.convert_physical_to_bytes(
65
87
  self.physical_constant_value, encode_state, bit_position=bit_position_int)
66
88
 
67
- def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
89
+ @override
90
+ def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
68
91
  # Decode value
69
- phys_val = super().decode_from_pdu(decode_state)
92
+ phys_val = super()._decode_positioned_from_pdu(decode_state)
70
93
 
71
94
  # Check if decoded value matches expected value
72
95
  if phys_val != self.physical_constant_value:
73
- warnings.warn(
96
+ odxraise(
74
97
  f"Physical constant parameter does not match! "
75
98
  f"The parameter {self.short_name} expected physical value "
76
99
  f"{self.physical_constant_value!r} but got {phys_val!r} "
77
100
  f"at byte position {decode_state.cursor_byte_position} "
78
- f"in coded message {decode_state.coded_message.hex()}.",
79
- DecodeError,
80
- stacklevel=1,
81
- )
101
+ f"in coded message {decode_state.coded_message.hex()}.", DecodeError)
82
102
  return phys_val
@@ -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.")