odxtools 9.3.0__py3-none-any.whl → 9.4.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/companyrevisioninfo.py +1 -1
  2. odxtools/comparaminstance.py +1 -6
  3. odxtools/comparamspec.py +3 -2
  4. odxtools/comparamsubset.py +3 -5
  5. odxtools/dataobjectproperty.py +12 -6
  6. odxtools/decodestate.py +120 -26
  7. odxtools/description.py +19 -2
  8. odxtools/diagcodedtype.py +9 -2
  9. odxtools/diagcomm.py +4 -4
  10. odxtools/diaglayercontainer.py +2 -2
  11. odxtools/diaglayers/diaglayerraw.py +2 -2
  12. odxtools/diaglayers/hierarchyelement.py +2 -0
  13. odxtools/diagnostictroublecode.py +4 -8
  14. odxtools/diagservice.py +70 -4
  15. odxtools/diagvariable.py +45 -7
  16. odxtools/encodestate.py +147 -51
  17. odxtools/encoding.py +56 -0
  18. odxtools/functionalclass.py +7 -2
  19. odxtools/inputparam.py +9 -3
  20. odxtools/leadinglengthinfotype.py +4 -0
  21. odxtools/minmaxlengthtype.py +57 -36
  22. odxtools/modification.py +3 -2
  23. odxtools/odxcategory.py +2 -2
  24. odxtools/odxlink.py +31 -7
  25. odxtools/odxtypes.py +1 -1
  26. odxtools/outputparam.py +8 -3
  27. odxtools/parameters/matchingrequestparameter.py +1 -0
  28. odxtools/parameters/physicalconstantparameter.py +1 -0
  29. odxtools/parameters/reservedparameter.py +1 -0
  30. odxtools/parameters/tableentryparameter.py +15 -4
  31. odxtools/parameters/tablekeyparameter.py +20 -17
  32. odxtools/paramlengthinfotype.py +5 -3
  33. odxtools/physicaltype.py +2 -1
  34. odxtools/scaleconstr.py +4 -4
  35. odxtools/standardlengthtype.py +98 -22
  36. odxtools/statetransition.py +24 -3
  37. odxtools/structure.py +10 -2
  38. odxtools/swvariable.py +3 -1
  39. odxtools/table.py +55 -3
  40. odxtools/tablerow.py +91 -8
  41. odxtools/templates/macros/printDOP.xml.jinja2 +2 -2
  42. odxtools/templates/macros/printDescription.xml.jinja2 +5 -1
  43. odxtools/templates/macros/printDiagLayer.xml.jinja2 +1 -1
  44. odxtools/templates/macros/printDiagVariable.xml.jinja2 +12 -3
  45. odxtools/templates/macros/printFunctionalClass.xml.jinja2 +4 -0
  46. odxtools/templates/macros/printParentRef.xml.jinja2 +27 -0
  47. odxtools/templates/macros/printProtocol.xml.jinja2 +1 -1
  48. odxtools/templates/macros/printService.xml.jinja2 +30 -0
  49. odxtools/templates/macros/printStructure.xml.jinja2 +2 -1
  50. odxtools/templates/macros/printTable.xml.jinja2 +43 -0
  51. odxtools/templates/macros/printUnitSpec.xml.jinja2 +4 -0
  52. odxtools/unit.py +8 -12
  53. odxtools/unitspec.py +5 -2
  54. odxtools/version.py +2 -2
  55. {odxtools-9.3.0.dist-info → odxtools-9.4.0.dist-info}/METADATA +1 -1
  56. {odxtools-9.3.0.dist-info → odxtools-9.4.0.dist-info}/RECORD +60 -59
  57. {odxtools-9.3.0.dist-info → odxtools-9.4.0.dist-info}/LICENSE +0 -0
  58. {odxtools-9.3.0.dist-info → odxtools-9.4.0.dist-info}/WHEEL +0 -0
  59. {odxtools-9.3.0.dist-info → odxtools-9.4.0.dist-info}/entry_points.txt +0 -0
  60. {odxtools-9.3.0.dist-info → odxtools-9.4.0.dist-info}/top_level.txt +0 -0
odxtools/diagvariable.py CHANGED
@@ -9,11 +9,13 @@ from .commrelation import CommRelation
9
9
  from .element import IdentifiableElement
10
10
  from .exceptions import odxrequire
11
11
  from .nameditemlist import NamedItemList
12
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
12
+ from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
13
13
  from .odxtypes import odxstr_to_bool
14
14
  from .snrefcontext import SnRefContext
15
15
  from .specialdatagroup import SpecialDataGroup
16
16
  from .swvariable import SwVariable
17
+ from .table import Table
18
+ from .tablerow import TableRow
17
19
  from .utils import dataclass_fields_asdict
18
20
  from .variablegroup import VariableGroup
19
21
 
@@ -32,15 +34,30 @@ class DiagVariable(IdentifiableElement):
32
34
  """
33
35
 
34
36
  admin_data: Optional[AdminData]
35
- variable_group_ref: OdxLinkRef
37
+ variable_group_ref: Optional[OdxLinkRef]
36
38
  sw_variables: List[SwVariable]
39
+
40
+ # a diag variable must specify either COMM-RELATIONS or a
41
+ # reference to a table row
37
42
  comm_relations: List[CommRelation]
38
- #snref_to_tablerow: Optional[SnrefToTableRow] # TODO
43
+
44
+ # these are nested inside the SNREF-TO-TABLEROW tag
45
+ table_snref: Optional[str]
46
+ table_row_snref: Optional[str]
47
+
39
48
  sdgs: List[SpecialDataGroup]
40
49
  is_read_before_write_raw: Optional[bool]
41
50
 
42
51
  @property
43
- def variable_group(self) -> VariableGroup:
52
+ def table(self) -> Optional[Table]:
53
+ return self._table
54
+
55
+ @property
56
+ def table_row(self) -> Optional[TableRow]:
57
+ return self._table_row
58
+
59
+ @property
60
+ def variable_group(self) -> Optional[VariableGroup]:
44
61
  return self._variable_group
45
62
 
46
63
  @property
@@ -52,8 +69,7 @@ class DiagVariable(IdentifiableElement):
52
69
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
53
70
 
54
71
  admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
55
- variable_group_ref = odxrequire(
56
- OdxLinkRef.from_et(et_element.find("VARIABLE-GROUP-REF"), doc_frags))
72
+ variable_group_ref = OdxLinkRef.from_et(et_element.find("VARIABLE-GROUP-REF"), doc_frags)
57
73
  sw_variables = NamedItemList([
58
74
  SwVariable.from_et(swv_elem, doc_frags)
59
75
  for swv_elem in et_element.iterfind("SW-VARIABLES/SW-VARIABLE")
@@ -62,6 +78,16 @@ class DiagVariable(IdentifiableElement):
62
78
  CommRelation.from_et(cr_elem, doc_frags)
63
79
  for cr_elem in et_element.iterfind("COMM-RELATIONS/COMM-RELATION")
64
80
  ]
81
+
82
+ table_snref = None
83
+ table_row_snref = None
84
+ if (snref_to_tablerow_elem := et_element.find("SNREF-TO-TABLEROW")) is not None:
85
+ table_snref_elem = odxrequire(snref_to_tablerow_elem.find("TABLE-SNREF"))
86
+ table_snref = odxrequire(table_snref_elem.attrib.get("SHORT-NAME"))
87
+
88
+ table_row_snref_elem = odxrequire(snref_to_tablerow_elem.find("TABLE-ROW-SNREF"))
89
+ table_row_snref = odxrequire(table_row_snref_elem.attrib.get("SHORT-NAME"))
90
+
65
91
  sdgs = [
66
92
  SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
67
93
  ]
@@ -72,6 +98,8 @@ class DiagVariable(IdentifiableElement):
72
98
  variable_group_ref=variable_group_ref,
73
99
  sw_variables=sw_variables,
74
100
  comm_relations=comm_relations,
101
+ table_snref=table_snref,
102
+ table_row_snref=table_row_snref,
75
103
  sdgs=sdgs,
76
104
  is_read_before_write_raw=is_read_before_write_raw,
77
105
  **kwargs)
@@ -91,7 +119,9 @@ class DiagVariable(IdentifiableElement):
91
119
  return result
92
120
 
93
121
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
94
- self._variable_group = odxlinks.resolve(self.variable_group_ref, VariableGroup)
122
+ self._variable_group = None
123
+ if self.variable_group_ref is not None:
124
+ self._variable_group = odxlinks.resolve(self.variable_group_ref, VariableGroup)
95
125
 
96
126
  if self.admin_data is not None:
97
127
  self.admin_data._resolve_odxlinks(odxlinks)
@@ -111,3 +141,11 @@ class DiagVariable(IdentifiableElement):
111
141
 
112
142
  for cr in self.comm_relations:
113
143
  cr._resolve_snrefs(context)
144
+
145
+ self._table = None
146
+ self._table_row = None
147
+ if self.table_snref is not None:
148
+ ddds = odxrequire(context.diag_layer).diag_data_dictionary_spec
149
+ self._table = resolve_snref(self.table_snref, ddds.tables, Table)
150
+ self._table_row = resolve_snref(
151
+ odxrequire(self.table_row_snref), self._table.table_rows, TableRow)
odxtools/encodestate.py CHANGED
@@ -3,6 +3,7 @@ import warnings
3
3
  from dataclasses import dataclass, field
4
4
  from typing import TYPE_CHECKING, Dict, List, Optional, SupportsBytes, Tuple
5
5
 
6
+ from .encoding import Encoding, get_string_encoding
6
7
  from .exceptions import EncodeError, OdxWarning, odxassert, odxraise
7
8
  from .odxtypes import AtomicOdxType, DataType, ParameterValue
8
9
 
@@ -86,6 +87,7 @@ class EncodeState:
86
87
  internal_value: AtomicOdxType,
87
88
  bit_length: int,
88
89
  base_data_type: DataType,
90
+ base_type_encoding: Optional[Encoding],
89
91
  is_highlow_byte_order: bool,
90
92
  used_mask: Optional[bytes],
91
93
  ) -> None:
@@ -93,63 +95,139 @@ class EncodeState:
93
95
 
94
96
  raw_value: AtomicOdxType
95
97
 
96
- # Check that bytes and strings actually fit into the bit length
98
+ # Deal with raw byte fields, ...
97
99
  if base_data_type == DataType.A_BYTEFIELD:
98
100
  if not isinstance(internal_value, (bytes, bytearray, SupportsBytes)):
99
- odxraise()
100
- if 8 * len(internal_value) > bit_length:
101
- raise EncodeError(f"The bytefield {internal_value.hex()} is too large "
102
- f"({len(internal_value)} bytes)."
103
- f" The maximum length is {bit_length//8}.")
104
- raw_value = bytes(internal_value)
105
- elif base_data_type == DataType.A_ASCIISTRING:
106
- if not isinstance(internal_value, str):
107
- odxraise()
101
+ odxraise(f"{internal_value!r} is not a bytefield", EncodeError)
102
+ return
108
103
 
109
- # The spec says ASCII, meaning only byte values 0-127.
110
- # But in practice, vendors use iso-8859-1, aka latin-1
111
- # reason being iso-8859-1 never fails since it has a valid
112
- # character mapping for every possible byte sequence.
113
- raw_value = internal_value.encode("iso-8859-1")
104
+ odxassert(
105
+ base_type_encoding in (None, Encoding.NONE, Encoding.BCD_P, Encoding.BCD_UP),
106
+ f"Illegal encoding '{base_type_encoding}' for A_BYTEFIELD")
107
+
108
+ # note that we do not ensure that BCD-encoded byte fields
109
+ # only represent "legal" values
110
+ raw_value = bytes(internal_value)
114
111
 
115
112
  if 8 * len(raw_value) > bit_length:
116
- raise EncodeError(f"The string {repr(internal_value)} is too large."
117
- f" The maximum number of characters is {bit_length//8}.")
118
- elif base_data_type == DataType.A_UTF8STRING:
113
+ odxraise(
114
+ f"The value '{internal_value!r}' cannot be encoded using "
115
+ f"{bit_length} bits.", EncodeError)
116
+ raw_value = raw_value[0:bit_length // 8]
117
+
118
+ # ... string types, ...
119
+ elif base_data_type in (DataType.A_UTF8STRING, DataType.A_ASCIISTRING,
120
+ DataType.A_UNICODE2STRING):
119
121
  if not isinstance(internal_value, str):
120
- odxraise()
122
+ odxraise(f"The internal value '{internal_value!r}' is not a string", EncodeError)
123
+ internal_value = str(internal_value)
121
124
 
122
- raw_value = internal_value.encode("utf-8")
125
+ str_encoding = get_string_encoding(base_data_type, base_type_encoding,
126
+ is_highlow_byte_order)
127
+ if str_encoding is not None:
128
+ raw_value = internal_value.encode(str_encoding)
129
+ else:
130
+ raw_value = b""
123
131
 
124
132
  if 8 * len(raw_value) > bit_length:
125
- raise EncodeError(f"The string {repr(internal_value)} is too large."
126
- f" The maximum number of bytes is {bit_length//8}.")
133
+ odxraise(
134
+ f"The value '{internal_value!r}' cannot be encoded using "
135
+ f"{bit_length} bits.", EncodeError)
136
+ raw_value = raw_value[0:bit_length // 8]
127
137
 
128
- elif base_data_type == DataType.A_UNICODE2STRING:
129
- if not isinstance(internal_value, str):
130
- odxraise()
138
+ # ... signed integers, ...
139
+ elif base_data_type == DataType.A_INT32:
140
+ if not isinstance(internal_value, int):
141
+ odxraise(
142
+ f"Internal value must be of integer type, not {type(internal_value).__name__}",
143
+ EncodeError)
144
+ internal_value = int(internal_value)
145
+
146
+ if base_type_encoding == Encoding.ONEC:
147
+ # one-complement
148
+ if internal_value >= 0:
149
+ raw_value = internal_value
150
+ else:
151
+ mask = (1 << bit_length) - 1
152
+ raw_value = mask + internal_value
153
+ elif base_type_encoding in (None, Encoding.TWOC):
154
+ # two-complement
155
+ if internal_value >= 0:
156
+ raw_value = internal_value
157
+ else:
158
+ mask = (1 << bit_length) - 1
159
+ raw_value = mask + internal_value + 1
160
+ elif base_type_encoding == Encoding.SM:
161
+ # sign-magnitude
162
+ if internal_value >= 0:
163
+ raw_value = internal_value
164
+ else:
165
+ raw_value = (1 << (bit_length - 1)) + abs(internal_value)
166
+ else:
167
+ odxraise(
168
+ f"Illegal encoding ({base_type_encoding and base_type_encoding.value}) specified for "
169
+ f"{base_data_type.value}")
131
170
 
132
- text_encoding = "utf-16-be" if is_highlow_byte_order else "utf-16-le"
133
- raw_value = internal_value.encode(text_encoding)
171
+ if base_type_encoding == Encoding.BCD_P:
172
+ raw_value = self.__encode_bcd_p(abs(internal_value))
173
+ elif base_type_encoding == Encoding.BCD_UP:
174
+ raw_value = self.__encode_bcd_up(abs(internal_value))
175
+ else:
176
+ raw_value = internal_value
134
177
 
135
- if 8 * len(raw_value) > bit_length:
136
- raise EncodeError(f"The string {repr(internal_value)} is too large."
137
- f" The maximum number of characters is {bit_length//16}.")
178
+ if raw_value.bit_length() > bit_length:
179
+ odxraise(
180
+ f"The value '{internal_value!r}' cannot be encoded using "
181
+ f"{bit_length} bits.", EncodeError)
182
+ raw_value &= (1 << bit_length) - 1
183
+
184
+ # ... unsigned integers, ...
185
+ elif base_data_type == DataType.A_UINT32:
186
+ if not isinstance(internal_value, int) or internal_value < 0:
187
+ odxraise(f"Internal value must be a positive integer, not {internal_value!r}")
188
+ internal_value = abs(int(internal_value))
189
+
190
+ if base_type_encoding == Encoding.BCD_P:
191
+ # packed BCD
192
+ raw_value = self.__encode_bcd_p(internal_value)
193
+ elif base_type_encoding == Encoding.BCD_UP:
194
+ # unpacked BCD
195
+ raw_value = self.__encode_bcd_up(internal_value)
196
+ elif base_type_encoding in (None, Encoding.NONE):
197
+ # no encoding
198
+ raw_value = internal_value
199
+ else:
200
+ odxraise(f"Illegal encoding ({base_type_encoding}) specified for "
201
+ f"{base_data_type.value}")
202
+
203
+ raw_value = internal_value
204
+
205
+ if raw_value.bit_length() > bit_length:
206
+ odxraise(
207
+ f"The value '{internal_value!r}' cannot be encoded using "
208
+ f"{bit_length} bits.", EncodeError)
209
+ raw_value &= (1 << bit_length) - 1
210
+
211
+ # ... and others (floating point values)
138
212
  else:
139
- raw_value = internal_value
213
+ odxassert(base_data_type in (DataType.A_FLOAT32, DataType.A_FLOAT64))
214
+ odxassert(base_type_encoding in (None, Encoding.NONE))
140
215
 
141
- # If the bit length is zero, return empty bytes
216
+ if base_data_type == DataType.A_FLOAT32 and bit_length != 32:
217
+ odxraise(f"Illegal bit length for a float32 object ({bit_length})")
218
+ bit_length = 32
219
+ elif base_data_type == DataType.A_FLOAT64 and bit_length != 64:
220
+ odxraise(f"Illegal bit length for a float64 object ({bit_length})")
221
+ bit_length = 64
222
+
223
+ raw_value = float(internal_value)
224
+
225
+ # If the bit length is zero, encode an empty value
142
226
  if bit_length == 0:
143
- if (base_data_type.value in [
144
- DataType.A_INT32, DataType.A_UINT32, DataType.A_FLOAT32, DataType.A_FLOAT64
145
- ] and base_data_type.value != 0):
146
- odxraise(
147
- f"The number {repr(internal_value)} cannot be encoded into {bit_length} bits.",
148
- EncodeError)
149
227
  self.emplace_bytes(b'')
150
228
  return
151
229
 
152
- char = base_data_type.bitstruct_format_letter
230
+ format_char = base_data_type.bitstruct_format_letter
153
231
  padding = (8 - ((bit_length + self.cursor_bit_position) % 8)) % 8
154
232
  odxassert((0 <= padding and padding < 8 and
155
233
  (padding + bit_length + self.cursor_bit_position) % 8 == 0),
@@ -157,19 +235,17 @@ class EncodeState:
157
235
  left_pad = f"p{padding}" if padding > 0 else ""
158
236
 
159
237
  # actually encode the value
160
- coded = bitstruct.pack(f"{left_pad}{char}{bit_length}", raw_value)
238
+ coded = bitstruct.pack(f"{left_pad}{format_char}{bit_length}", raw_value)
161
239
 
162
240
  # create the raw mask of used bits for numeric objects
163
241
  used_mask_raw = used_mask
164
- if base_data_type in [DataType.A_INT32, DataType.A_UINT32
165
- ] and (self.cursor_bit_position != 0 or
166
- (self.cursor_bit_position + bit_length) % 8 != 0):
167
- if used_mask is None:
168
- tmp = (1 << bit_length) - 1
169
- else:
170
- tmp = int.from_bytes(used_mask, "big")
171
- tmp <<= self.cursor_bit_position
172
242
 
243
+ if used_mask_raw is None:
244
+ used_mask_raw = ((1 << bit_length) - 1).to_bytes((bit_length + 7) // 8, "big")
245
+
246
+ if self.cursor_bit_position != 0:
247
+ tmp = int.from_bytes(used_mask_raw, "big")
248
+ tmp <<= self.cursor_bit_position
173
249
  used_mask_raw = tmp.to_bytes((self.cursor_bit_position + bit_length + 7) // 8, "big")
174
250
 
175
251
  # apply byte order to numeric objects
@@ -177,9 +253,7 @@ class EncodeState:
177
253
  DataType.A_INT32, DataType.A_UINT32, DataType.A_FLOAT32, DataType.A_FLOAT64
178
254
  ]:
179
255
  coded = coded[::-1]
180
-
181
- if used_mask_raw is not None:
182
- used_mask_raw = used_mask_raw[::-1]
256
+ used_mask_raw = used_mask_raw[::-1]
183
257
 
184
258
  self.cursor_bit_position = 0
185
259
  self.emplace_bytes(coded, obj_used_mask=used_mask_raw)
@@ -233,3 +307,25 @@ class EncodeState:
233
307
  self.used_mask[pos + i] |= obj_used_mask[i]
234
308
 
235
309
  self.cursor_byte_position += len(new_data)
310
+
311
+ @staticmethod
312
+ def __encode_bcd_p(value: int) -> int:
313
+ result = 0
314
+ shift = 0
315
+ while value > 0:
316
+ result |= (value % 10) << shift
317
+ shift += 4
318
+ value //= 10
319
+
320
+ return result
321
+
322
+ @staticmethod
323
+ def __encode_bcd_up(value: int) -> int:
324
+ result = 0
325
+ shift = 0
326
+ while value > 0:
327
+ result |= (value % 10) << shift
328
+ shift += 8
329
+ value //= 10
330
+
331
+ return result
odxtools/encoding.py ADDED
@@ -0,0 +1,56 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from enum import Enum
3
+ from typing import Optional
4
+
5
+ from .exceptions import odxraise
6
+ from .odxtypes import DataType
7
+
8
+
9
+ class Encoding(Enum):
10
+ BCD_P = "BCD-P"
11
+ BCD_UP = "BCD-UP"
12
+
13
+ ONEC = "1C"
14
+ TWOC = "2C"
15
+ SM = "SM"
16
+
17
+ UTF8 = "UTF-8"
18
+ UCS2 = "UCS-2"
19
+ ISO_8859_1 = "ISO-8859-1"
20
+ ISO_8859_2 = "ISO-8859-2"
21
+ WINDOWS_1252 = "WINDOWS-1252"
22
+
23
+ NONE = "NONE"
24
+
25
+
26
+ def get_string_encoding(base_data_type: DataType, base_type_encoding: Optional[Encoding],
27
+ is_highlow_byte_order: bool) -> Optional[str]:
28
+ """If the encoding is for a string, return the value for
29
+ `str.encode()`/`str.decode()` to convert the string object
30
+ to/from a byte array
31
+ """
32
+
33
+ # note that the spec disallows certain combinations of
34
+ # base_data_type and encoding (e.g., A_ASCIISTRING encoded
35
+ # using UTF-8). Since in python3 strings are always
36
+ # capable of the full unicode character set, odxtools
37
+ # ignores these restrictions...
38
+ if base_type_encoding == Encoding.UTF8 or (base_data_type == DataType.A_UTF8STRING and
39
+ base_type_encoding is None):
40
+ return "utf-8"
41
+ elif base_type_encoding == Encoding.UCS2 or (base_data_type == DataType.A_UNICODE2STRING and
42
+ base_type_encoding is None):
43
+ return "utf-16-be" if is_highlow_byte_order else "utf-16-le"
44
+ elif base_type_encoding == Encoding.ISO_8859_1 or (base_data_type == DataType.A_ASCIISTRING and
45
+ base_type_encoding is None):
46
+ return "iso-8859-1"
47
+ elif base_type_encoding == Encoding.ISO_8859_2:
48
+ return "iso-8859-2"
49
+ elif base_type_encoding == Encoding.WINDOWS_1252:
50
+ return "cp1252"
51
+ else:
52
+ odxraise(f"Specified illegal encoding {base_type_encoding} for {base_data_type.value} "
53
+ f"string object")
54
+ return "iso-8859-1"
55
+
56
+ return None
@@ -1,8 +1,9 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, List
3
+ from typing import Any, Dict, List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
+ from .admindata import AdminData
6
7
  from .element import IdentifiableElement
7
8
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
8
9
  from .snrefcontext import SnRefContext
@@ -15,13 +16,17 @@ class FunctionalClass(IdentifiableElement):
15
16
  Corresponds to FUNCT-CLASS.
16
17
  """
17
18
 
19
+ admin_data: Optional[AdminData]
20
+
18
21
  @staticmethod
19
22
  def from_et(et_element: ElementTree.Element,
20
23
  doc_frags: List[OdxDocFragment]) -> "FunctionalClass":
21
24
 
22
25
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
23
26
 
24
- return FunctionalClass(**kwargs)
27
+ admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
28
+
29
+ return FunctionalClass(admin_data=admin_data, **kwargs)
25
30
 
26
31
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
27
32
  return {self.odx_id: self}
odxtools/inputparam.py CHANGED
@@ -3,6 +3,8 @@ from dataclasses import dataclass
3
3
  from typing import Any, Dict, List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
+ from deprecation import deprecated
7
+
6
8
  from .dopbase import DopBase
7
9
  from .element import NamedElement
8
10
  from .exceptions import odxrequire
@@ -38,12 +40,16 @@ class InputParam(NamedElement):
38
40
  return {}
39
41
 
40
42
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
41
- self._dop_base = odxlinks.resolve(self.dop_base_ref, DopBase)
43
+ self._dop = odxlinks.resolve(self.dop_base_ref, DopBase)
42
44
 
43
45
  def _resolve_snrefs(self, context: SnRefContext) -> None:
44
46
  pass
45
47
 
46
48
  @property
47
- def dop_base(self) -> DopBase:
49
+ def dop(self) -> DopBase:
48
50
  """The data object property describing this parameter."""
49
- return self._dop_base
51
+ return self._dop
52
+
53
+ @deprecated(details="use .dop") # type: ignore[misc]
54
+ def dop_base(self) -> DopBase:
55
+ return self._dop
@@ -72,6 +72,7 @@ class LeadingLengthInfoType(DiagCodedType):
72
72
  used_mask=None,
73
73
  bit_length=self.bit_length,
74
74
  base_data_type=DataType.A_UINT32,
75
+ base_type_encoding=None,
75
76
  is_highlow_byte_order=self.is_highlow_byte_order,
76
77
  )
77
78
 
@@ -80,6 +81,7 @@ class LeadingLengthInfoType(DiagCodedType):
80
81
  used_mask=None,
81
82
  bit_length=8 * byte_length,
82
83
  base_data_type=self.base_data_type,
84
+ base_type_encoding=None,
83
85
  is_highlow_byte_order=self.is_highlow_byte_order,
84
86
  )
85
87
 
@@ -90,6 +92,7 @@ class LeadingLengthInfoType(DiagCodedType):
90
92
  byte_length = decode_state.extract_atomic_value(
91
93
  bit_length=self.bit_length,
92
94
  base_data_type=DataType.A_UINT32, # length is an integer
95
+ base_type_encoding=None,
93
96
  is_highlow_byte_order=self.is_highlow_byte_order,
94
97
  )
95
98
 
@@ -102,6 +105,7 @@ class LeadingLengthInfoType(DiagCodedType):
102
105
  value = decode_state.extract_atomic_value(
103
106
  bit_length=8 * byte_length,
104
107
  base_data_type=self.base_data_type,
108
+ base_type_encoding=None,
105
109
  is_highlow_byte_order=self.is_highlow_byte_order,
106
110
  )
107
111