odxtools 7.2.0__py3-none-any.whl → 7.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 (49) hide show
  1. odxtools/basicstructure.py +10 -7
  2. odxtools/cli/_print_utils.py +3 -3
  3. odxtools/cli/browse.py +4 -2
  4. odxtools/cli/list.py +3 -3
  5. odxtools/commrelation.py +122 -0
  6. odxtools/comparaminstance.py +1 -1
  7. odxtools/comparamspec.py +1 -2
  8. odxtools/compumethods/linearsegment.py +0 -2
  9. odxtools/database.py +17 -11
  10. odxtools/decodestate.py +8 -2
  11. odxtools/diaglayer.py +23 -17
  12. odxtools/diaglayerraw.py +116 -23
  13. odxtools/diagnostictroublecode.py +2 -2
  14. odxtools/diagservice.py +33 -20
  15. odxtools/diagvariable.py +104 -0
  16. odxtools/dtcdop.py +39 -14
  17. odxtools/dyndefinedspec.py +179 -0
  18. odxtools/encodestate.py +14 -2
  19. odxtools/environmentdatadescription.py +137 -16
  20. odxtools/exceptions.py +10 -1
  21. odxtools/multiplexer.py +92 -56
  22. odxtools/multiplexercase.py +6 -5
  23. odxtools/multiplexerdefaultcase.py +7 -6
  24. odxtools/odxlink.py +19 -47
  25. odxtools/odxtypes.py +1 -1
  26. odxtools/parameterinfo.py +2 -2
  27. odxtools/parameters/nrcconstparameter.py +28 -37
  28. odxtools/parameters/systemparameter.py +1 -1
  29. odxtools/parameters/tablekeyparameter.py +11 -4
  30. odxtools/servicebinner.py +1 -1
  31. odxtools/specialdatagroup.py +1 -1
  32. odxtools/swvariable.py +21 -0
  33. odxtools/templates/macros/printComparam.xml.jinja2 +4 -2
  34. odxtools/templates/macros/printCompuMethod.xml.jinja2 +1 -8
  35. odxtools/templates/macros/printDiagVariable.xml.jinja2 +66 -0
  36. odxtools/templates/macros/printDynDefinedSpec.xml.jinja2 +48 -0
  37. odxtools/templates/macros/printEcuVariantPattern.xml.jinja2 +1 -1
  38. odxtools/templates/macros/printParam.xml.jinja2 +7 -8
  39. odxtools/templates/macros/printService.xml.jinja2 +3 -2
  40. odxtools/templates/macros/printSingleEcuJob.xml.jinja2 +2 -2
  41. odxtools/templates/macros/printVariant.xml.jinja2 +30 -13
  42. odxtools/variablegroup.py +22 -0
  43. odxtools/version.py +2 -2
  44. {odxtools-7.2.0.dist-info → odxtools-7.4.0.dist-info}/METADATA +18 -18
  45. {odxtools-7.2.0.dist-info → odxtools-7.4.0.dist-info}/RECORD +49 -42
  46. {odxtools-7.2.0.dist-info → odxtools-7.4.0.dist-info}/WHEEL +1 -1
  47. {odxtools-7.2.0.dist-info → odxtools-7.4.0.dist-info}/LICENSE +0 -0
  48. {odxtools-7.2.0.dist-info → odxtools-7.4.0.dist-info}/entry_points.txt +0 -0
  49. {odxtools-7.2.0.dist-info → odxtools-7.4.0.dist-info}/top_level.txt +0 -0
@@ -3,13 +3,13 @@ from dataclasses import dataclass
3
3
  from typing import Any, Dict, List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
- from .basicstructure import BasicStructure
7
6
  from .compumethods.limit import Limit
8
7
  from .element import NamedElement
9
8
  from .exceptions import odxrequire
10
9
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
11
10
  from .odxtypes import AtomicOdxType, DataType
12
11
  from .snrefcontext import SnRefContext
12
+ from .structure import Structure
13
13
  from .utils import dataclass_fields_asdict
14
14
 
15
15
 
@@ -23,7 +23,7 @@ class MultiplexerCase(NamedElement):
23
23
  upper_limit: Limit
24
24
 
25
25
  def __post_init__(self) -> None:
26
- self._structure: BasicStructure
26
+ self._structure: Optional[Structure]
27
27
 
28
28
  @staticmethod
29
29
  def from_et(et_element: ElementTree.Element,
@@ -62,8 +62,9 @@ class MultiplexerCase(NamedElement):
62
62
 
63
63
  def _mux_case_resolve_odxlinks(self, odxlinks: OdxLinkDatabase, *,
64
64
  key_physical_type: DataType) -> None:
65
+ self._structure = None
65
66
  if self.structure_ref:
66
- self._structure = odxlinks.resolve(self.structure_ref)
67
+ self._structure = odxlinks.resolve(self.structure_ref, Structure)
67
68
 
68
69
  self.lower_limit.set_value_type(key_physical_type)
69
70
  self.upper_limit.set_value_type(key_physical_type)
@@ -71,12 +72,12 @@ class MultiplexerCase(NamedElement):
71
72
  def _resolve_snrefs(self, context: SnRefContext) -> None:
72
73
  if self.structure_snref:
73
74
  ddds = odxrequire(context.diag_layer).diag_data_dictionary_spec
74
- self._structure = resolve_snref(self.structure_snref, ddds.structures, BasicStructure)
75
+ self._structure = resolve_snref(self.structure_snref, ddds.structures, Structure)
75
76
 
76
77
  def applies(self, value: AtomicOdxType) -> bool:
77
78
  return self.lower_limit.complies_to_lower(value) \
78
79
  and self.upper_limit.complies_to_upper(value)
79
80
 
80
81
  @property
81
- def structure(self) -> BasicStructure:
82
+ def structure(self) -> Optional[Structure]:
82
83
  return self._structure
@@ -3,11 +3,11 @@ from dataclasses import dataclass
3
3
  from typing import Any, Dict, List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
- from .basicstructure import BasicStructure
7
6
  from .element import NamedElement
8
7
  from .exceptions import odxrequire
9
8
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
10
9
  from .snrefcontext import SnRefContext
10
+ from .structure import Structure
11
11
  from .utils import dataclass_fields_asdict
12
12
 
13
13
 
@@ -18,12 +18,12 @@ class MultiplexerDefaultCase(NamedElement):
18
18
  structure_snref: Optional[str]
19
19
 
20
20
  def __post_init__(self) -> None:
21
- self._structure: BasicStructure
21
+ self._structure: Optional[Structure]
22
22
 
23
23
  @staticmethod
24
24
  def from_et(et_element: ElementTree.Element,
25
25
  doc_frags: List[OdxDocFragment]) -> "MultiplexerDefaultCase":
26
- """Reads a Default Case for a Multiplexer."""
26
+ """Reads a default case for a multiplexer."""
27
27
  kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
28
28
 
29
29
  structure_ref = OdxLinkRef.from_et(et_element.find("STRUCTURE-REF"), doc_frags)
@@ -38,14 +38,15 @@ class MultiplexerDefaultCase(NamedElement):
38
38
  return {}
39
39
 
40
40
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
41
+ self._structure = None
41
42
  if self.structure_ref is not None:
42
- self._structure = odxlinks.resolve(self.structure_ref)
43
+ self._structure = odxlinks.resolve(self.structure_ref, Structure)
43
44
 
44
45
  def _resolve_snrefs(self, context: SnRefContext) -> None:
45
46
  if self.structure_snref:
46
47
  ddds = odxrequire(context.diag_layer).diag_data_dictionary_spec
47
- self._structure = resolve_snref(self.structure_snref, ddds.structures, BasicStructure)
48
+ self._structure = resolve_snref(self.structure_snref, ddds.structures, Structure)
48
49
 
49
50
  @property
50
- def structure(self) -> BasicStructure:
51
+ def structure(self) -> Optional[Structure]:
51
52
  return self._structure
odxtools/odxlink.py CHANGED
@@ -4,30 +4,14 @@ from dataclasses import dataclass
4
4
  from typing import Any, Dict, Iterable, List, Optional, Type, TypeVar, overload
5
5
  from xml.etree import ElementTree
6
6
 
7
- from .exceptions import OdxWarning, odxassert, odxraise
7
+ from .exceptions import OdxWarning, odxassert, odxraise, odxrequire
8
8
  from .nameditemlist import OdxNamed, TNamed
9
9
 
10
10
 
11
11
  @dataclass(frozen=True)
12
12
  class OdxDocFragment:
13
13
  doc_name: str
14
- doc_type: Optional[str]
15
-
16
- def __eq__(self, other: Any) -> bool:
17
- if other is None:
18
- # if the other document fragment is not specified, we
19
- # treat it as a wildcard...
20
- return True
21
-
22
- if not isinstance(other, OdxDocFragment):
23
- return False
24
-
25
- # the ODX spec says that the doctype can be ignored...
26
- return self.doc_name == other.doc_name
27
-
28
- def __hash__(self) -> int:
29
- # only the document name is relevant for the hash value
30
- return hash(self.doc_name) + hash(self.doc_type)
14
+ doc_type: str
31
15
 
32
16
 
33
17
  @dataclass(frozen=True)
@@ -59,10 +43,12 @@ class OdxLinkId:
59
43
  if not isinstance(other, OdxLinkId):
60
44
  return False
61
45
 
62
- # we do take the document fragment into consideration here, because
63
- # document fragments are handled using separate sub-databases,
64
- # i.e. the same OdxId object can be put into all of them.
65
- return self.local_id == other.local_id
46
+ # if the local ID is different, the whole id is different
47
+ if self.local_id != other.local_id:
48
+ return False
49
+
50
+ # the document fragments must be identical for the IDs to be identical
51
+ return self.doc_fragments == other.doc_fragments
66
52
 
67
53
  def __str__(self) -> str:
68
54
  return f"OdxLinkId('{self.local_id}')"
@@ -120,6 +106,7 @@ class OdxLinkRef:
120
106
 
121
107
  id_ref = et.attrib.get("ID-REF")
122
108
  if id_ref is None:
109
+ odxraise(f"Tag {et.tag} is not a ODXLINK reference")
123
110
  return None
124
111
 
125
112
  doc_ref = et.attrib.get("DOCREF")
@@ -133,7 +120,7 @@ class OdxLinkRef:
133
120
  # reference, use it, else use the document fragment containing
134
121
  # the reference.
135
122
  if doc_ref is not None:
136
- doc_frags = [OdxDocFragment(doc_ref, doc_type)]
123
+ doc_frags = [OdxDocFragment(doc_ref, odxrequire(doc_type))]
137
124
  else:
138
125
  doc_frags = source_doc_frags
139
126
 
@@ -147,32 +134,19 @@ class OdxLinkRef:
147
134
  def __str__(self) -> str:
148
135
  return f"OdxLinkRef('{self.ref_id}')"
149
136
 
150
- def __contains__(self, odx_id: OdxLinkId) -> bool:
151
- """
152
- Returns true iff a given OdxLinkId object is referenced.
153
- """
154
-
155
- # we must reference at to at least of the ID's document
156
- # fragments
157
- if not any(ref_doc in odx_id.doc_fragments for ref_doc in self.ref_docs):
158
- return False
159
-
160
- # the local ID of the reference and the object ID must match
161
- return odx_id.local_id == self.ref_id
162
-
163
137
 
164
138
  T = TypeVar("T")
165
139
 
166
140
 
167
141
  class OdxLinkDatabase:
168
142
  """
169
- A database holding all objects which ehibit OdxLinkIds
143
+ A database holding all objects which exhibit OdxLinkIds
170
144
 
171
- This can resolve references to such.
145
+ This can resolve ODXLINK references.
172
146
  """
173
147
 
174
148
  def __init__(self) -> None:
175
- self._db: Dict[OdxDocFragment, Dict[OdxLinkId, Any]] = {}
149
+ self._db: Dict[OdxDocFragment, Dict[str, Any]] = {}
176
150
 
177
151
  @overload
178
152
  def resolve(self, ref: OdxLinkRef, expected_type: None = None) -> Any:
@@ -189,13 +163,12 @@ class OdxLinkDatabase:
189
163
  If the database does not contain any object which is referred to, a
190
164
  KeyError exception is raised.
191
165
  """
192
- odx_id = OdxLinkId(ref.ref_id, ref.ref_docs)
193
166
  for ref_frag in reversed(ref.ref_docs):
194
167
  doc_frag_db = self._db.get(ref_frag)
195
168
  if doc_frag_db is None:
196
169
  # No object featured by the database uses the document
197
170
  # fragment mentioned by the reference. This should not
198
- # happen for correct databases...
171
+ # happen for correct ODX databases...
199
172
  warnings.warn(
200
173
  f"Warning: Unknown document fragment {ref_frag} "
201
174
  f"when resolving reference {ref}",
@@ -204,8 +177,9 @@ class OdxLinkDatabase:
204
177
  )
205
178
  continue
206
179
 
207
- obj = doc_frag_db.get(odx_id)
208
- if obj is not None:
180
+ # locate an object exhibiting with the referenced local ID
181
+ # in the ID database for the document fragment
182
+ if (obj := doc_frag_db.get(ref.ref_id)) is not None:
209
183
  if expected_type is not None:
210
184
  odxassert(isinstance(obj, expected_type))
211
185
 
@@ -234,7 +208,6 @@ class OdxLinkDatabase:
234
208
  is returned.
235
209
  """
236
210
 
237
- odx_id = OdxLinkId(ref.ref_id, ref.ref_docs)
238
211
  for ref_frag in reversed(ref.ref_docs):
239
212
  doc_frag_db = self._db.get(ref_frag)
240
213
  if doc_frag_db is None:
@@ -249,8 +222,7 @@ class OdxLinkDatabase:
249
222
  )
250
223
  continue
251
224
 
252
- obj = doc_frag_db.get(odx_id)
253
- if obj is not None:
225
+ if (obj := doc_frag_db.get(ref.ref_id)) is not None:
254
226
  if expected_type is not None:
255
227
  odxassert(isinstance(obj, expected_type))
256
228
 
@@ -272,7 +244,7 @@ class OdxLinkDatabase:
272
244
  if doc_frag not in self._db:
273
245
  self._db[doc_frag] = {}
274
246
 
275
- self._db[doc_frag][odx_id] = obj
247
+ self._db[doc_frag][odx_id.local_id] = obj
276
248
 
277
249
 
278
250
  @overload
odxtools/odxtypes.py CHANGED
@@ -235,7 +235,7 @@ class DataType(Enum):
235
235
  expected_type = self.python_type
236
236
  if isinstance(value, expected_type):
237
237
  return True
238
- elif expected_type == float and isinstance(value, (int, float)):
238
+ elif expected_type is float and isinstance(value, (int, float)):
239
239
  return True
240
240
  elif self == DataType.A_BYTEFIELD and isinstance(value, (bytearray, bytes)):
241
241
  return True
odxtools/parameterinfo.py CHANGED
@@ -108,8 +108,8 @@ def parameter_info(param_list: Iterable[Parameter], quoted_names: bool = False)
108
108
  of.write(f"multiplexer; choices:\n")
109
109
  for mux_case in dop.cases:
110
110
  of.write(f" ({repr(mux_case.short_name)}, {{\n")
111
- of.write(
112
- textwrap.indent(parameter_info(mux_case.structure.parameters, True), " "))
111
+ if (struc := mux_case.structure) is not None:
112
+ of.write(textwrap.indent(parameter_info(struc.parameters, True), " "))
113
113
  of.write(f" }})\n")
114
114
  continue
115
115
 
@@ -1,7 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
- import warnings
3
2
  from dataclasses import dataclass
4
- from typing import Any, Dict, List, Optional, cast
3
+ from typing import Any, Dict, List, Optional
5
4
  from xml.etree import ElementTree
6
5
 
7
6
  from typing_extensions import override
@@ -10,7 +9,7 @@ from ..createanydiagcodedtype import create_any_diag_coded_type_from_et
10
9
  from ..decodestate import DecodeState
11
10
  from ..diagcodedtype import DiagCodedType
12
11
  from ..encodestate import EncodeState
13
- from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
12
+ from ..exceptions import DecodeMismatch, EncodeError, odxraise, odxrequire
14
13
  from ..odxlink import OdxDocFragment, OdxLinkId
15
14
  from ..odxtypes import AtomicOdxType, DataType, ParameterValue
16
15
  from ..utils import dataclass_fields_asdict
@@ -19,7 +18,8 @@ from .parameter import Parameter, ParameterType
19
18
 
20
19
  @dataclass
21
20
  class NrcConstParameter(Parameter):
22
- """A param of type NRC-CONST defines a set of values to be matched for a negative response to apply.
21
+ """A parameter of type NRC-CONST defines a set of values to be
22
+ matched for a negative response object to apply
23
23
 
24
24
  The behaviour of NRC-CONST parameters is similar to CODED-CONST
25
25
  parameters in that they allow to specify which coding objects
@@ -88,49 +88,40 @@ class NrcConstParameter(Parameter):
88
88
  @override
89
89
  def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
90
90
  encode_state: EncodeState) -> None:
91
- coded_value: ParameterValue
91
+ # NRC-CONST parameters are not encoding any value on its
92
+ # own. instead, it is supposed to overlap with a value
93
+ # parameter.
92
94
  if physical_value is not None:
93
- if physical_value not in self.coded_values:
94
- odxraise(
95
- f"The value of parameter '{self.short_name}' must "
96
- f" be one of {self.coded_values} (is: {physical_value!r})", EncodeError)
97
- coded_value = self.coded_values[0]
98
- else:
99
- coded_value = physical_value
100
- else:
101
- # If the user did not select a value, the value of the
102
- # this parameter is set by another parameter which
103
- # overlaps with it. We thus just move the cursor.
104
- bit_pos = encode_state.cursor_bit_position
105
- bit_len = self.diag_coded_type.get_static_bit_length()
106
-
107
- if bit_len is None:
108
- odxraise("The diag coded type of NRC-CONST parameters must "
109
- "exhibit a static size")
110
- return
111
-
112
- encode_state.cursor_byte_position += (bit_pos + bit_len + 7) // 8
113
- encode_state.cursor_bit_position = 0
95
+ odxraise("The value of NRC-CONST parameters cannot be set directly!", EncodeError)
96
+
97
+ # TODO (?): extract the parameter and check if it is one of
98
+ # the values of self.coded_values. if not, throw an
99
+ # EncodeMismatch exception! This is probably a bad idea
100
+ # because the parameter which determines the value of the
101
+ # NRC-CONST might possibly be specified after the NRC-CONST.
102
+
103
+ # move the cursor forward by the size of the parameter
104
+ bit_pos = encode_state.cursor_bit_position
105
+ bit_len = self.diag_coded_type.get_static_bit_length()
106
+
107
+ if bit_len is None:
108
+ odxraise("The diag coded type of NRC-CONST parameters must "
109
+ "exhibit a static size")
114
110
  return
115
111
 
116
- self.diag_coded_type.encode_into_pdu(cast(AtomicOdxType, coded_value), encode_state)
112
+ encode_state.cursor_byte_position += (bit_pos + bit_len + 7) // 8
113
+ encode_state.cursor_bit_position = 0
114
+
115
+ encode_state.emplace_bytes(b'', self.short_name)
117
116
 
118
117
  @override
119
118
  def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> AtomicOdxType:
120
- # Extract coded values
119
+ # Extract coded value
121
120
  coded_value = self.diag_coded_type.decode_from_pdu(decode_state)
122
121
 
123
122
  # Check if the coded value in the message is correct.
124
123
  if coded_value not in self.coded_values:
125
- warnings.warn(
126
- f"Coded constant parameter does not match! "
127
- f"The parameter {self.short_name} expected a coded "
128
- f"value in {str(self.coded_values)} but got {str(coded_value)} "
129
- f"at byte position {decode_state.cursor_byte_position} "
130
- f"in coded message {decode_state.coded_message.hex()}.",
131
- DecodeError,
132
- stacklevel=1,
133
- )
124
+ raise DecodeMismatch(f"NRC-CONST parameter {self.short_name} does not apply")
134
125
 
135
126
  return coded_value
136
127
 
@@ -26,7 +26,7 @@ class SystemParameter(ParameterWithDOP):
26
26
 
27
27
  kwargs = dataclass_fields_asdict(ParameterWithDOP.from_et(et_element, doc_frags))
28
28
 
29
- sysparam = odxrequire(et_element.findtext("SYSPARAM"))
29
+ sysparam = odxrequire(et_element.get("SYSPARAM"))
30
30
 
31
31
  return SystemParameter(sysparam=sysparam, **kwargs)
32
32
 
@@ -99,13 +99,20 @@ class TableKeyParameter(Parameter):
99
99
 
100
100
  if self.table_snref is not None:
101
101
  tables = odxrequire(context.diag_layer).diag_data_dictionary_spec.tables
102
- self._table = resolve_snref(self.table_snref, tables, Table)
102
+ if TYPE_CHECKING:
103
+ self._table = resolve_snref(self.table_snref, tables, Table)
104
+ else:
105
+ self._table = resolve_snref(self.table_snref, tables)
103
106
  if self.table_row_snref is not None:
104
107
  # make sure that we know the table to which the table row
105
108
  # SNREF is relative to.
106
- table = odxrequire(self._table,
107
- "If a table-row is referenced, a table must also be referenced.")
108
- self._table_row = resolve_snref(self.table_row_snref, table.table_rows, TableRow)
109
+ table = odxrequire(
110
+ self._table, "If a table row is referenced via short name, a table must "
111
+ "be referenced as well")
112
+ if TYPE_CHECKING:
113
+ self._table_row = resolve_snref(self.table_row_snref, table.table_rows, TableRow)
114
+ else:
115
+ self._table_row = resolve_snref(self.table_row_snref, table.table_rows)
109
116
 
110
117
  @property
111
118
  def table(self) -> "Table":
odxtools/servicebinner.py CHANGED
@@ -91,7 +91,7 @@ class ServiceBinner:
91
91
  """
92
92
  result = StringIO()
93
93
  result.write("[ ")
94
- result.write(", ".join([f"0x{x}" for x in self._service_groups if x is not None]))
94
+ result.write(", ".join([f"0x{x:x}" for x in self._service_groups if x is not None]))
95
95
  result.write(" ]")
96
96
 
97
97
  return result.getvalue()
@@ -51,7 +51,7 @@ class SpecialDataGroup:
51
51
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
52
52
  result = {}
53
53
 
54
- if self.sdg_caption is not None:
54
+ if self.sdg_caption_ref is None and self.sdg_caption is not None:
55
55
  result.update(self.sdg_caption._build_odxlinks())
56
56
 
57
57
  for val in self.values:
odxtools/swvariable.py ADDED
@@ -0,0 +1,21 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import List, Optional
4
+ from xml.etree import ElementTree
5
+
6
+ from .element import NamedElement
7
+ from .odxlink import OdxDocFragment
8
+ from .utils import dataclass_fields_asdict
9
+
10
+
11
+ @dataclass
12
+ class SwVariable(NamedElement):
13
+ origin: Optional[str]
14
+
15
+ @staticmethod
16
+ def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "SwVariable":
17
+ kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
18
+
19
+ origin = et_element.findtext("ORIGIN")
20
+
21
+ return SwVariable(origin=origin, **kwargs)
@@ -44,7 +44,9 @@
44
44
  {{make_xml_attrib("DISPLAY-LEVEL", cp.display_level)}}{#- #}
45
45
  CPUSAGE="{{cp.cpusage.value}}">
46
46
  {{ peid.printElementIdSubtags(cp)|indent(1) }}
47
- <PHYSICAL-DEFAULT-VALUE>{{cp.physical_default_value}}</PHYSICAL-DEFAULT-VALUE>
47
+ {%- if cp.physical_default_value is not none %}
48
+ <PHYSICAL-DEFAULT-VALUE>{{cp.physical_default_value | e}}</PHYSICAL-DEFAULT-VALUE>
49
+ {%- endif %}
48
50
  <DATA-OBJECT-PROP-REF ID-REF="{{cp.dop_ref.ref_id}}" />
49
51
  </COMPARAM>
50
52
  {%- endmacro %}
@@ -61,7 +63,7 @@
61
63
  {%- for sub_cp in cp.subparams %}
62
64
  {{- printAnyComparam(sub_cp) | indent(1, first=True) }}
63
65
  {%- endfor %}
64
- {%- if cp.physical_default_value is not none %}
66
+ {%- if cp.physical_default_value is not none %}
65
67
  {{ printComplexValue(cp.physical_default_value, "COMPLEX-PHYSICAL-DEFAULT-VALUE") | indent(1) }}
66
68
  {%- endif %}
67
69
  </COMPLEX-COMPARAM>
@@ -18,14 +18,7 @@
18
18
  {%- if limit_obj.value_raw is none %}
19
19
  {#- #}/>
20
20
  {%- else %}
21
- {#- #}>
22
- {%- if hasattr(limit_obj._value, 'hex') -%}
23
- {#- bytes or bytarray limit #}
24
- {{- limit_obj._value.hex().upper() }}
25
- {%- else -%}
26
- {{- limit_obj._value }}
27
- {%- endif -%}
28
- </{{tag_name}}>
21
+ {#- #}>{{- limit_obj.value_raw }}</{{tag_name}}>
29
22
  {%- endif -%}
30
23
  {%- endif -%}
31
24
  {%- endmacro -%}
@@ -0,0 +1,66 @@
1
+ {#- -*- mode: sgml; tab-width: 2; indent-tabs-mode: nil -*-
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ -#}
5
+ {%- import('macros/printElementId.xml.jinja2') as peid %}
6
+ {%- import('macros/printAdminData.xml.jinja2') as pad %}
7
+ {%- import('macros/printDescription.xml.jinja2') as pd %}
8
+
9
+ {%- macro printDiagVariable(diag_var) -%}
10
+ <DIAG-VARIABLE>
11
+ {{ peid.printElementIdSubtags(diag_variable)|indent(2) }}
12
+ {%- if diag_variable.admin_data is not none %}
13
+ {{ pad.printAdminData(diag_variable.admin_data)|indent(2) }}
14
+ {%- endif %}
15
+ <VARIABLE-GROUP-REF ID-REF="{{ diag_var.ref_id }}" />
16
+ {%- if diag_variable.sw_variables %}
17
+ <SW-VARIABLES>
18
+ {%- for sw_var in diag_variable.sw_variables %}
19
+ <SW-VARIABLE>
20
+ {{ peid.printElementIdSubtags(sw_var)|indent(6) }}
21
+ {%- if sw_var.origin is not none %}
22
+ <ORIGIN>{{ sw_var.origin }}</ORIGIN>
23
+ {%- endif %}
24
+ </SW-VARIABLE>
25
+ {%- endfor %}
26
+ </SW-VARIABLES>
27
+ {%- endif %}
28
+ {%- if diag_variable.comm_relations %}
29
+ <COMM-RELATIONS>
30
+ {%- for comm_relation in diag_variable.comm_relations %}
31
+ <COMM-RELATION>
32
+ {{ pd.printDescription(comm_relation.description) }}
33
+ <RELATION-TYPE>{{comm_relation.relation_type}}</RELATION-TYPE>
34
+ {%- if comm_relation.diag_comm_ref is not none %}
35
+ <DIAG-COMM-REF ID-REF="{{comm_relation.diag_comm_ref.ref_id}}" />
36
+ {%- endif %}
37
+ {%- if comm_relation.diag_comm_snref is not none %}
38
+ <DIAG-COMM-SNREF SHORT-NAME="{{comm_relation.diag_comm_snref}}" />
39
+ {%- endif %}
40
+ {%- if comm_relation.in_param_if_ref is not none %}
41
+ <IN-PARAM-IF-REF ID-REF="{{comm_relation.in_param_if_ref.ref_id}}" />
42
+ {%- endif %}
43
+ {%- if comm_relation.in_param_if_snref is not none %}
44
+ <IN-PARAM-IF-SNREF SHORT-NAME="{{comm_relation.in_param_if_snref}}" />
45
+ {%- endif %}
46
+ {%- if comm_relation.out_param_if_ref is not none %}
47
+ <OUT-PARAM-IF-REF ID-REF="{{comm_relation.out_param_if_ref.ref_id}}" />
48
+ {%- endif %}
49
+ {%- if comm_relation.out_param_if_snref is not none %}
50
+ <OUT-PARAM-IF-SNREF SHORT-NAME="{{comm_relation.out_param_if_snref}}" />
51
+ {%- endif %}
52
+ {%- if comm_relation.value_type_raw is not none %}
53
+ <VALUE-TYPE>{{comm_relation.value_type_raw.value}}</VALUE-TYPE>
54
+ {%- endif %}
55
+ <COMM-RELATION>
56
+ {%- endfor %}
57
+ </COMM-RELATIONS>
58
+ {%- endif %}
59
+ </DIAG-VARIABLE>
60
+ {%- endmacro -%}
61
+
62
+ {%- macro printVariableGroup(var_group) -%}
63
+ <VARIABLE-GROUP>
64
+ {{ peid.printElementIdSubtags(diag_variable)|indent(2) }}
65
+ </VARIABLE-GROUP>
66
+ {%- endmacro -%}
@@ -0,0 +1,48 @@
1
+ {#- -*- mode: sgml; tab-width: 2; indent-tabs-mode: nil -*-
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ -#}
5
+
6
+ {%- macro printDynDefinedSpec(dd_spec) -%}
7
+ <DYN-DEFINED-SPEC>
8
+ {%- if dd_spec.dyn_id_def_mode_infos %}
9
+ <DYN-ID-DEF-MODE-INFOS>
10
+ {%- for diddmi in dd_spec.dyn_id_def_mode_infos %}
11
+ <DYN-ID-DEF-MODE-INFO>
12
+ <DEF-MODE>{{ diddmi.def_mode }}</DEF-MODE>
13
+ {%- if diddmi.clear_dyn_def_message_ref is not none %}
14
+ <CLEAR-DYN-DEF-MESSAGE-REF ID-REF="{{diddmi.clear_dyn_def_message_ref.ref_id}}" />
15
+ {%- endif %}
16
+ {%- if diddmi.clear_dyn_def_message_snref is not none %}
17
+ <CLEAR-DYN-DEF-MESSAGE-SNREF SHORT-NAME="{{diddmi.clear_dyn_def_message_snref}}" />
18
+ {%- endif %}
19
+ {%- if diddmi.read_dyn_def_message_ref is not none %}
20
+ <READ-DYN-DEF-MESSAGE-REF ID-REF="{{diddmi.read_dyn_def_message_ref.ref_id}}" />
21
+ {%- endif %}
22
+ {%- if diddmi.read_dyn_def_message_snref is not none %}
23
+ <READ-DYN-DEF-MESSAGE-SNREF SHORT-NAME="{{diddmi.read_dyn_def_message_snref}}" />
24
+ {%- endif %}
25
+ {%- if diddmi.supported_dyn_ids %}
26
+ <SUPPORTED-DYN-IDS>
27
+ {%- for dynid in diddmi.supported_dyn_ids %}
28
+ <SUPPORTED-DYN-ID>{{ dynid.hex() }}</SUPPORTED-DYN-ID>
29
+ {%- endfor %}
30
+ </SUPPORTED-DYN-IDS>
31
+ {%- endif %}
32
+ {%- if diddmi.selection_table_refs %}
33
+ <SELECTION-TABLE-REFS>
34
+ {%- for seltref in diddmi.selection_table_refs %}
35
+ {%- if hasattr(seltref, "ref_id") %}
36
+ <SELECTION-TABLE-REF ID-REF="{{ seltref.ref_id }}" />
37
+ {%- else %}
38
+ <SELECTION-TABLE-SNREF SHORT-NAME="{{ seltref }}" />
39
+ {%- endif %}
40
+ {%- endfor %}
41
+ </SELECTION-TABLE-REFS>
42
+ {%- endif %}
43
+ </DYN-ID-DEF-MODE-INFO>
44
+ {%- endfor %}
45
+ </DYN-ID-DEF-MODE-INFOS>
46
+ {%- endif %}
47
+ </DYN-DEFINED-SPEC>
48
+ {%- endmacro -%}
@@ -9,7 +9,7 @@
9
9
 
10
10
  {%- macro printMatchingParameter(mp) -%}
11
11
  <MATCHING-PARAMETER>
12
- <EXPECTED-VALUE>{{mp.expected_value}}</EXPECTED-VALUE>
12
+ <EXPECTED-VALUE>{{mp.expected_value | e}}</EXPECTED-VALUE>
13
13
  <DIAG-COMM-SNREF SHORT-NAME="{{mp.diag_comm_snref}}" />
14
14
  {#- TODO: OUT-PARAM-IF-SNPATHREF #}
15
15
  <OUT-PARAM-IF-SNREF SHORT-NAME="{{mp.out_param_if}}" />
@@ -35,8 +35,6 @@
35
35
  {%- endif %}
36
36
  {%- if param.coded_value is defined %}
37
37
  <CODED-VALUE>{{param.coded_value}}</CODED-VALUE>
38
- {%- elif param.physical_constant_value_raw is defined %}
39
- <PHYS-CONSTANT-VALUE>{{param.physical_constant_value_raw}}</PHYS-CONSTANT-VALUE>
40
38
  {%- elif param.coded_values is defined %}
41
39
  <CODED-VALUES>
42
40
  {%- for coded_value in param.coded_values %}
@@ -44,8 +42,11 @@
44
42
  {%- endfor %}
45
43
  </CODED-VALUES>
46
44
  {%- endif %}
47
- {%- if param.physical_default_value_raw %}
48
- <PHYSICAL-DEFAULT-VALUE>{{param.physical_default_value_raw}}</PHYSICAL-DEFAULT-VALUE>
45
+ {%- if param.physical_constant_value_raw is defined %}
46
+ <PHYS-CONSTANT-VALUE>{{param.physical_constant_value_raw}}</PHYS-CONSTANT-VALUE>
47
+ {%- endif %}
48
+ {%- if param.physical_default_value_raw is defined and param.physical_default_value_raw is not none %}
49
+ <PHYSICAL-DEFAULT-VALUE>{{param.physical_default_value_raw | e}}</PHYSICAL-DEFAULT-VALUE>
49
50
  {%- endif %}
50
51
  {%- if param.dop_ref %}
51
52
  <DOP-REF ID-REF="{{param.dop_ref.ref_id}}"/>
@@ -53,10 +54,8 @@
53
54
  <DOP-SNREF SN="{{param.dop_snref}}"/>
54
55
  {%- elif param.diag_coded_type is defined %}
55
56
  {{pdop.printDiagCodedType(param.diag_coded_type)|indent(2)}}
56
- {%- elif param.parameter_type != "MATCHING-REQUEST-PARAM" %}
57
- {%- if param.bit_length is defined and param.bit_length is not none %}
58
- <BIT-LENGTH>{{param.bit_length}}</BIT-LENGTH>
59
- {%- endif %}
57
+ {%- elif param.bit_length is defined and param.bit_length is not none %}
58
+ <BIT-LENGTH>{{param.bit_length}}</BIT-LENGTH>
60
59
  {%- endif %}
61
60
  {%- if param.parameter_type == "TABLE-KEY" %}
62
61
  {%- if param.table_ref %}