odxtools 6.6.1__py3-none-any.whl → 9.3.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 (222) hide show
  1. odxtools/__init__.py +7 -5
  2. odxtools/additionalaudience.py +3 -5
  3. odxtools/admindata.py +5 -7
  4. odxtools/audience.py +10 -13
  5. odxtools/basecomparam.py +3 -5
  6. odxtools/basicstructure.py +55 -241
  7. odxtools/cli/_parser_utils.py +16 -1
  8. odxtools/cli/_print_utils.py +169 -134
  9. odxtools/cli/browse.py +127 -103
  10. odxtools/cli/compare.py +114 -87
  11. odxtools/cli/decode.py +2 -1
  12. odxtools/cli/dummy_sub_parser.py +3 -1
  13. odxtools/cli/find.py +2 -1
  14. odxtools/cli/list.py +26 -16
  15. odxtools/cli/main.py +1 -0
  16. odxtools/cli/snoop.py +32 -6
  17. odxtools/codec.py +211 -0
  18. odxtools/commrelation.py +122 -0
  19. odxtools/companydata.py +5 -7
  20. odxtools/companydocinfo.py +7 -8
  21. odxtools/companyrevisioninfo.py +3 -5
  22. odxtools/companyspecificinfo.py +8 -9
  23. odxtools/comparam.py +4 -6
  24. odxtools/comparaminstance.py +14 -14
  25. odxtools/comparamspec.py +16 -54
  26. odxtools/comparamsubset.py +22 -62
  27. odxtools/complexcomparam.py +5 -7
  28. odxtools/compumethods/compucodecompumethod.py +63 -0
  29. odxtools/compumethods/compuconst.py +31 -0
  30. odxtools/compumethods/compudefaultvalue.py +27 -0
  31. odxtools/compumethods/compuinternaltophys.py +56 -0
  32. odxtools/compumethods/compuinversevalue.py +7 -0
  33. odxtools/compumethods/compumethod.py +94 -15
  34. odxtools/compumethods/compuphystointernal.py +56 -0
  35. odxtools/compumethods/compurationalcoeffs.py +20 -9
  36. odxtools/compumethods/compuscale.py +67 -32
  37. odxtools/compumethods/createanycompumethod.py +31 -172
  38. odxtools/compumethods/identicalcompumethod.py +31 -6
  39. odxtools/compumethods/limit.py +70 -36
  40. odxtools/compumethods/linearcompumethod.py +70 -181
  41. odxtools/compumethods/linearsegment.py +190 -0
  42. odxtools/compumethods/ratfunccompumethod.py +106 -0
  43. odxtools/compumethods/ratfuncsegment.py +87 -0
  44. odxtools/compumethods/scalelinearcompumethod.py +132 -26
  45. odxtools/compumethods/scaleratfunccompumethod.py +113 -0
  46. odxtools/compumethods/tabintpcompumethod.py +123 -92
  47. odxtools/compumethods/texttablecompumethod.py +117 -57
  48. odxtools/createanydiagcodedtype.py +10 -67
  49. odxtools/database.py +167 -87
  50. odxtools/dataobjectproperty.py +25 -32
  51. odxtools/decodestate.py +14 -17
  52. odxtools/description.py +47 -0
  53. odxtools/determinenumberofitems.py +4 -5
  54. odxtools/diagcodedtype.py +37 -106
  55. odxtools/diagcomm.py +24 -12
  56. odxtools/diagdatadictionaryspec.py +120 -96
  57. odxtools/diaglayercontainer.py +46 -54
  58. odxtools/diaglayers/basevariant.py +128 -0
  59. odxtools/diaglayers/basevariantraw.py +123 -0
  60. odxtools/diaglayers/diaglayer.py +432 -0
  61. odxtools/{diaglayerraw.py → diaglayers/diaglayerraw.py} +105 -120
  62. odxtools/diaglayers/diaglayertype.py +42 -0
  63. odxtools/diaglayers/ecushareddata.py +96 -0
  64. odxtools/diaglayers/ecushareddataraw.py +87 -0
  65. odxtools/diaglayers/ecuvariant.py +124 -0
  66. odxtools/diaglayers/ecuvariantraw.py +129 -0
  67. odxtools/diaglayers/functionalgroup.py +110 -0
  68. odxtools/diaglayers/functionalgroupraw.py +106 -0
  69. odxtools/{diaglayer.py → diaglayers/hierarchyelement.py} +273 -472
  70. odxtools/diaglayers/hierarchyelementraw.py +58 -0
  71. odxtools/diaglayers/protocol.py +64 -0
  72. odxtools/diaglayers/protocolraw.py +91 -0
  73. odxtools/diagnostictroublecode.py +8 -9
  74. odxtools/diagservice.py +57 -44
  75. odxtools/diagvariable.py +113 -0
  76. odxtools/docrevision.py +5 -7
  77. odxtools/dopbase.py +15 -15
  78. odxtools/dtcdop.py +170 -50
  79. odxtools/dynamicendmarkerfield.py +134 -0
  80. odxtools/dynamiclengthfield.py +47 -42
  81. odxtools/dyndefinedspec.py +177 -0
  82. odxtools/dynenddopref.py +38 -0
  83. odxtools/ecuvariantmatcher.py +6 -7
  84. odxtools/element.py +13 -15
  85. odxtools/encodestate.py +199 -22
  86. odxtools/endofpdufield.py +31 -18
  87. odxtools/environmentdata.py +8 -1
  88. odxtools/environmentdatadescription.py +198 -36
  89. odxtools/exceptions.py +11 -2
  90. odxtools/field.py +10 -10
  91. odxtools/functionalclass.py +3 -5
  92. odxtools/inputparam.py +3 -12
  93. odxtools/internalconstr.py +14 -5
  94. odxtools/isotp_state_machine.py +14 -6
  95. odxtools/leadinglengthinfotype.py +37 -18
  96. odxtools/library.py +66 -0
  97. odxtools/loadfile.py +64 -0
  98. odxtools/matchingparameter.py +3 -3
  99. odxtools/message.py +0 -7
  100. odxtools/minmaxlengthtype.py +61 -33
  101. odxtools/modification.py +3 -5
  102. odxtools/multiplexer.py +135 -75
  103. odxtools/multiplexercase.py +39 -18
  104. odxtools/multiplexerdefaultcase.py +15 -12
  105. odxtools/multiplexerswitchkey.py +4 -5
  106. odxtools/nameditemlist.py +33 -8
  107. odxtools/negoutputparam.py +3 -5
  108. odxtools/odxcategory.py +83 -0
  109. odxtools/odxlink.py +62 -53
  110. odxtools/odxtypes.py +93 -8
  111. odxtools/outputparam.py +5 -16
  112. odxtools/parameterinfo.py +219 -61
  113. odxtools/parameters/codedconstparameter.py +45 -32
  114. odxtools/parameters/createanyparameter.py +19 -193
  115. odxtools/parameters/dynamicparameter.py +25 -4
  116. odxtools/parameters/lengthkeyparameter.py +83 -25
  117. odxtools/parameters/matchingrequestparameter.py +48 -18
  118. odxtools/parameters/nrcconstparameter.py +76 -54
  119. odxtools/parameters/parameter.py +97 -73
  120. odxtools/parameters/parameterwithdop.py +41 -38
  121. odxtools/parameters/physicalconstantparameter.py +41 -20
  122. odxtools/parameters/reservedparameter.py +36 -18
  123. odxtools/parameters/systemparameter.py +74 -7
  124. odxtools/parameters/tableentryparameter.py +47 -7
  125. odxtools/parameters/tablekeyparameter.py +142 -55
  126. odxtools/parameters/tablestructparameter.py +79 -58
  127. odxtools/parameters/valueparameter.py +39 -21
  128. odxtools/paramlengthinfotype.py +56 -33
  129. odxtools/parentref.py +20 -3
  130. odxtools/physicaldimension.py +3 -8
  131. odxtools/progcode.py +26 -11
  132. odxtools/protstack.py +3 -5
  133. odxtools/py.typed +0 -0
  134. odxtools/relateddoc.py +7 -9
  135. odxtools/request.py +120 -10
  136. odxtools/response.py +123 -23
  137. odxtools/scaleconstr.py +14 -8
  138. odxtools/servicebinner.py +1 -1
  139. odxtools/singleecujob.py +12 -10
  140. odxtools/snrefcontext.py +29 -0
  141. odxtools/specialdata.py +3 -5
  142. odxtools/specialdatagroup.py +7 -9
  143. odxtools/specialdatagroupcaption.py +3 -6
  144. odxtools/standardlengthtype.py +80 -14
  145. odxtools/state.py +3 -5
  146. odxtools/statechart.py +13 -19
  147. odxtools/statetransition.py +8 -18
  148. odxtools/staticfield.py +107 -0
  149. odxtools/subcomponent.py +288 -0
  150. odxtools/swvariable.py +21 -0
  151. odxtools/table.py +9 -9
  152. odxtools/tablerow.py +30 -15
  153. odxtools/teammember.py +3 -5
  154. odxtools/templates/comparam-spec.odx-c.xml.jinja2 +4 -24
  155. odxtools/templates/comparam-subset.odx-cs.xml.jinja2 +5 -26
  156. odxtools/templates/diag_layer_container.odx-d.xml.jinja2 +15 -31
  157. odxtools/templates/{index.xml.xml.jinja2 → index.xml.jinja2} +1 -1
  158. odxtools/templates/macros/printAudience.xml.jinja2 +1 -1
  159. odxtools/templates/macros/printBaseVariant.xml.jinja2 +53 -0
  160. odxtools/templates/macros/printCompanyData.xml.jinja2 +4 -7
  161. odxtools/templates/macros/printComparam.xml.jinja2 +6 -4
  162. odxtools/templates/macros/printComparamRef.xml.jinja2 +5 -12
  163. odxtools/templates/macros/printCompuMethod.xml.jinja2 +147 -0
  164. odxtools/templates/macros/printDOP.xml.jinja2 +27 -137
  165. odxtools/templates/macros/printDescription.xml.jinja2 +18 -0
  166. odxtools/templates/macros/printDiagComm.xml.jinja2 +1 -1
  167. odxtools/templates/macros/printDiagLayer.xml.jinja2 +222 -0
  168. odxtools/templates/macros/printDiagVariable.xml.jinja2 +66 -0
  169. odxtools/templates/macros/printDynDefinedSpec.xml.jinja2 +48 -0
  170. odxtools/templates/macros/printDynamicEndmarkerField.xml.jinja2 +16 -0
  171. odxtools/templates/macros/printDynamicLengthField.xml.jinja2 +1 -1
  172. odxtools/templates/macros/printEcuSharedData.xml.jinja2 +30 -0
  173. odxtools/templates/macros/printEcuVariant.xml.jinja2 +53 -0
  174. odxtools/templates/macros/printEcuVariantPattern.xml.jinja2 +1 -1
  175. odxtools/templates/macros/printElementId.xml.jinja2 +8 -3
  176. odxtools/templates/macros/printEndOfPdu.xml.jinja2 +1 -1
  177. odxtools/templates/macros/printEnvDataDesc.xml.jinja2 +1 -1
  178. odxtools/templates/macros/printFunctionalClass.xml.jinja2 +1 -1
  179. odxtools/templates/macros/printFunctionalGroup.xml.jinja2 +40 -0
  180. odxtools/templates/macros/printHierarchyElement.xml.jinja2 +24 -0
  181. odxtools/templates/macros/printLibrary.xml.jinja2 +21 -0
  182. odxtools/templates/macros/printMux.xml.jinja2 +5 -3
  183. odxtools/templates/macros/printOdxCategory.xml.jinja2 +28 -0
  184. odxtools/templates/macros/printParam.xml.jinja2 +18 -19
  185. odxtools/templates/macros/printProtStack.xml.jinja2 +1 -1
  186. odxtools/templates/macros/printProtocol.xml.jinja2 +30 -0
  187. odxtools/templates/macros/printRequest.xml.jinja2 +1 -1
  188. odxtools/templates/macros/printResponse.xml.jinja2 +1 -1
  189. odxtools/templates/macros/printService.xml.jinja2 +3 -2
  190. odxtools/templates/macros/printSingleEcuJob.xml.jinja2 +5 -26
  191. odxtools/templates/macros/printSpecialData.xml.jinja2 +1 -1
  192. odxtools/templates/macros/printState.xml.jinja2 +1 -1
  193. odxtools/templates/macros/printStateChart.xml.jinja2 +1 -1
  194. odxtools/templates/macros/printStateTransition.xml.jinja2 +1 -1
  195. odxtools/templates/macros/printStaticField.xml.jinja2 +15 -0
  196. odxtools/templates/macros/printStructure.xml.jinja2 +1 -1
  197. odxtools/templates/macros/printSubComponent.xml.jinja2 +104 -0
  198. odxtools/templates/macros/printTable.xml.jinja2 +4 -5
  199. odxtools/templates/macros/printUnitSpec.xml.jinja2 +3 -5
  200. odxtools/uds.py +2 -10
  201. odxtools/unit.py +4 -8
  202. odxtools/unitgroup.py +3 -5
  203. odxtools/unitspec.py +17 -17
  204. odxtools/utils.py +38 -20
  205. odxtools/variablegroup.py +32 -0
  206. odxtools/version.py +2 -2
  207. odxtools/{write_pdx_file.py → writepdxfile.py} +22 -12
  208. odxtools/xdoc.py +3 -5
  209. {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/METADATA +44 -33
  210. odxtools-9.3.0.dist-info/RECORD +228 -0
  211. {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/WHEEL +1 -1
  212. odxtools/createcompanydatas.py +0 -17
  213. odxtools/createsdgs.py +0 -19
  214. odxtools/diaglayertype.py +0 -30
  215. odxtools/load_file.py +0 -13
  216. odxtools/load_odx_d_file.py +0 -6
  217. odxtools/load_pdx_file.py +0 -8
  218. odxtools/templates/macros/printVariant.xml.jinja2 +0 -208
  219. odxtools-6.6.1.dist-info/RECORD +0 -180
  220. {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/LICENSE +0 -0
  221. {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/entry_points.txt +0 -0
  222. {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/top_level.txt +0 -0
@@ -1,19 +1,20 @@
1
1
  # SPDX-License-Identifier: MIT
2
- import warnings
3
2
  from dataclasses import dataclass
4
- from typing import TYPE_CHECKING, Any, Dict, Optional, cast
3
+ from typing import Any, Dict, List, Optional, cast
4
+ from xml.etree import ElementTree
5
+
6
+ from typing_extensions import override
5
7
 
6
8
  from ..decodestate import DecodeState
7
9
  from ..encodestate import EncodeState
8
- from ..exceptions import EncodeError, OdxWarning, odxraise
9
- from ..odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
10
+ from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
11
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
10
12
  from ..odxtypes import ParameterValue
13
+ from ..snrefcontext import SnRefContext
14
+ from ..utils import dataclass_fields_asdict
11
15
  from .parameter import Parameter, ParameterType
12
16
  from .tablekeyparameter import TableKeyParameter
13
17
 
14
- if TYPE_CHECKING:
15
- from ..diaglayer import DiagLayer
16
-
17
18
 
18
19
  @dataclass
19
20
  class TableStructParameter(Parameter):
@@ -21,123 +22,146 @@ class TableStructParameter(Parameter):
21
22
  table_key_ref: Optional[OdxLinkRef]
22
23
  table_key_snref: Optional[str]
23
24
 
25
+ @staticmethod
26
+ @override
27
+ def from_et(et_element: ElementTree.Element,
28
+ doc_frags: List[OdxDocFragment]) -> "TableStructParameter":
29
+
30
+ kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
31
+
32
+ table_key_ref = OdxLinkRef.from_et(et_element.find("TABLE-KEY-REF"), doc_frags)
33
+ table_key_snref = None
34
+ if (table_key_snref_elem := et_element.find("TABLE-KEY-SNREF")) is not None:
35
+ table_key_snref = odxrequire(table_key_snref_elem.get("SHORT-NAME"))
36
+
37
+ return TableStructParameter(
38
+ table_key_ref=table_key_ref, table_key_snref=table_key_snref, **kwargs)
39
+
24
40
  def __post_init__(self) -> None:
25
41
  if self.table_key_ref is None and self.table_key_snref is None:
26
42
  odxraise("Either table_key_ref or table_key_snref must be defined.")
27
43
 
28
44
  @property
45
+ @override
29
46
  def parameter_type(self) -> ParameterType:
30
47
  return "TABLE-STRUCT"
31
48
 
49
+ @override
32
50
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
33
51
  return super()._build_odxlinks()
34
52
 
53
+ @override
35
54
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
36
55
  super()._resolve_odxlinks(odxlinks)
37
56
 
38
57
  if self.table_key_ref is not None:
39
- self._table_key = odxlinks.resolve(self.table_key_ref)
58
+ self._table_key = odxlinks.resolve(self.table_key_ref, TableKeyParameter)
40
59
 
41
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
42
- super()._resolve_snrefs(diag_layer)
60
+ @override
61
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
62
+ super()._resolve_snrefs(context)
43
63
 
44
64
  if self.table_key_snref is not None:
45
- warnings.warn(
46
- "Table keys cannot yet be defined using SNREFs"
47
- " in TableStructParameters.",
48
- OdxWarning,
49
- stacklevel=1)
65
+ self._table_key = resolve_snref(self.table_key_snref, odxrequire(context.parameters),
66
+ TableKeyParameter)
50
67
 
51
68
  @property
52
69
  def table_key(self) -> TableKeyParameter:
53
70
  return self._table_key
54
71
 
55
72
  @property
73
+ @override
56
74
  def is_required(self) -> bool:
57
75
  return True
58
76
 
59
77
  @property
78
+ @override
60
79
  def is_settable(self) -> bool:
61
80
  return True
62
81
 
63
- def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
64
- physical_value = encode_state.parameter_values.get(self.short_name)
82
+ @override
83
+ def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
84
+ encode_state: EncodeState) -> None:
65
85
 
66
- if not isinstance(physical_value, tuple) or \
86
+ if not isinstance(physical_value, (tuple, list)) or \
67
87
  len(physical_value) != 2 or \
68
88
  not isinstance(physical_value[0], str):
69
- raise EncodeError(f"The physical value of TableStructParameter 'self.short_name' "
70
- f"must be a tuple with the short name of the selected table "
71
- f"row as the first element and the physical value for the "
72
- f"row's structure or DOP as the second.")
89
+ odxraise(
90
+ f"The physical value of TableStructParameter 'self.short_name' "
91
+ f"must be a tuple containing the short name of the selected table "
92
+ f"row as the first element and the physical value for the "
93
+ f"row's structure or DOP as the second.", EncodeError)
73
94
 
74
95
  tr_short_name = physical_value[0]
75
96
 
76
97
  # make sure that the same table row is selected for all
77
98
  # TABLE-STRUCT parameters that are using the same key
78
99
  tk_short_name = self.table_key.short_name
79
- tk_value = encode_state.parameter_values.get(tk_short_name)
100
+ tk_value = encode_state.table_keys.get(tk_short_name)
80
101
  if tk_value is None:
81
102
  # no value for the key has been set yet. Set it to the
82
103
  # value which we are using right now
83
- encode_state.parameter_values[tk_short_name] = tr_short_name
104
+ encode_state.table_keys[tk_short_name] = tr_short_name
84
105
  elif tk_value != tr_short_name:
85
- raise EncodeError(f"Cannot determine a unique value for table key '{tk_short_name}': "
86
- f"Requested are '{tk_value}' and '{tr_short_name}'")
106
+ odxraise(
107
+ f"Cannot determine a unique value for table key '{tk_short_name}': "
108
+ f"Requested are '{tk_value}' and '{tr_short_name}'", EncodeError)
109
+ return
87
110
 
88
111
  # deal with the static case (i.e., the table row is selected
89
112
  # by the table key object itself)
90
- if self.table_key.table_row is not None and \
91
- self.table_key.table_row.short_name != tr_short_name:
92
- raise EncodeError(f"The selected table row for the {self.short_name} "
93
- f"parameter must be '{self.table_key.table_row.short_name}' "
94
- f"(is: '{tr_short_name}')")
113
+ if self.table_key.table_row is not None:
114
+ if tr_short_name is not None and self.table_key.table_row.short_name != tr_short_name:
115
+ odxraise(
116
+ f"The selected table row for the {self.short_name} "
117
+ f"parameter must be '{self.table_key.table_row.short_name}' "
118
+ f"instead of '{tr_short_name}'", EncodeError)
119
+ return
120
+
121
+ tr_short_name = self.table_key.table_row.short_name
95
122
 
96
123
  # encode the user specified value using the structure (or DOP)
97
124
  # of the selected table row
98
125
  table = self.table_key.table
99
126
  candidate_trs = [tr for tr in table.table_rows if tr.short_name == tr_short_name]
100
- if len(candidate_trs) != 1:
101
- raise EncodeError(f"Could not uniquely resolve a table row named "
102
- f"'{tr_short_name}' in table '{table.short_name}' ")
127
+ if len(candidate_trs) == 0:
128
+ odxraise(
129
+ f"Could not find a table row named "
130
+ f"'{tr_short_name}' in table '{table.short_name}'", EncodeError)
131
+ return
132
+ elif len(candidate_trs) > 1:
133
+ odxraise(
134
+ f"Found multiple table rows named "
135
+ f"'{tr_short_name}' in table '{table.short_name}'", EncodeError)
136
+
103
137
  tr = candidate_trs[0]
104
138
  tr_value = physical_value[1]
105
139
 
106
- bit_position = self.bit_position or 0
107
140
  if tr.structure is not None:
108
141
  # the selected table row references a structure
109
- inner_encode_state = EncodeState(
110
- coded_message=bytearray(b''),
111
- parameter_values=tr_value,
112
- triggering_request=encode_state.triggering_request)
113
-
114
- return tr.structure.convert_physical_to_bytes(
115
- tr_value, inner_encode_state, bit_position=bit_position)
142
+ tr.structure.encode_into_pdu(tr_value, encode_state)
143
+ return
116
144
 
117
145
  # if the table row does not reference a structure, it must
118
146
  # point to a DOP!
119
147
  if tr.dop is None:
120
- odxraise()
121
-
122
- return tr.dop.convert_physical_to_bytes(
123
- tr_value, encode_state=encode_state, bit_position=bit_position)
124
-
125
- def encode_into_pdu(self, encode_state: EncodeState) -> bytes:
126
- return super().encode_into_pdu(encode_state)
148
+ odxraise(f"Neither a structure nor a DOP has been defined for table row"
149
+ f"'{tr.short_name}'")
150
+ return
127
151
 
128
- def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
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
152
+ tr.dop.encode_into_pdu(tr_value, encode_state)
132
153
 
154
+ @override
155
+ def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
133
156
  # find the selected table row
134
157
  key_name = self.table_key.short_name
135
158
 
136
159
  decode_state.table_keys[key_name]
137
160
  table_row = decode_state.table_keys.get(key_name)
138
161
  if table_row is None:
139
- raise odxraise(f"No table key '{key_name}' found when decoding "
140
- f"table struct parameter '{str(self.short_name)}'")
162
+ odxraise(
163
+ f"No table key '{key_name}' found when decoding "
164
+ f"table struct parameter '{str(self.short_name)}'", DecodeError)
141
165
  dummy_val = cast(str, None), cast(int, None)
142
166
  return dummy_val
143
167
 
@@ -145,14 +169,11 @@ class TableStructParameter(Parameter):
145
169
  if table_row.dop is not None:
146
170
  dop = table_row.dop
147
171
  val = dop.decode_from_pdu(decode_state)
148
- decode_state.cursor_byte_position = max(decode_state.cursor_byte_position, orig_cursor)
149
172
  return (table_row.short_name, val)
150
173
  elif table_row.structure is not None:
151
174
  val = table_row.structure.decode_from_pdu(decode_state)
152
- decode_state.cursor_byte_position = max(decode_state.cursor_byte_position, orig_cursor)
153
175
  return (table_row.short_name, val)
154
176
  else:
155
177
  # the table row associated with the key neither defines a
156
178
  # DOP nor a structure -> ignore it
157
- decode_state.cursor_byte_position = max(decode_state.cursor_byte_position, orig_cursor)
158
179
  return (table_row.short_name, cast(int, None))
@@ -1,18 +1,20 @@
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 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 ..encodestate import EncodeState
7
- from ..exceptions import odxraise, odxrequire
8
- from ..odxlink import OdxLinkDatabase, OdxLinkId
9
- from ..odxtypes import AtomicOdxType
10
+ from ..exceptions import EncodeError, odxraise, odxrequire
11
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
12
+ from ..odxtypes import AtomicOdxType, ParameterValue
13
+ from ..snrefcontext import SnRefContext
14
+ from ..utils import dataclass_fields_asdict
10
15
  from .parameter import ParameterType
11
16
  from .parameterwithdop import ParameterWithDOP
12
17
 
13
- if TYPE_CHECKING:
14
- from ..diaglayer import DiagLayer
15
-
16
18
 
17
19
  @dataclass
18
20
  class ValueParameter(ParameterWithDOP):
@@ -21,18 +23,33 @@ class ValueParameter(ParameterWithDOP):
21
23
  def __post_init__(self) -> None:
22
24
  self._physical_default_value: Optional[AtomicOdxType] = None
23
25
 
26
+ @staticmethod
27
+ @override
28
+ def from_et(et_element: ElementTree.Element,
29
+ doc_frags: List[OdxDocFragment]) -> "ValueParameter":
30
+
31
+ kwargs = dataclass_fields_asdict(ParameterWithDOP.from_et(et_element, doc_frags))
32
+
33
+ physical_default_value_raw = et_element.findtext("PHYSICAL-DEFAULT-VALUE")
34
+
35
+ return ValueParameter(physical_default_value_raw=physical_default_value_raw, **kwargs)
36
+
24
37
  @property
38
+ @override
25
39
  def parameter_type(self) -> ParameterType:
26
40
  return "VALUE"
27
41
 
42
+ @override
28
43
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
29
44
  return super()._build_odxlinks()
30
45
 
46
+ @override
31
47
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
32
48
  super()._resolve_odxlinks(odxlinks)
33
49
 
34
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
35
- super()._resolve_snrefs(diag_layer)
50
+ @override
51
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
52
+ super()._resolve_snrefs(context)
36
53
 
37
54
  if self.physical_default_value_raw is not None:
38
55
  dop = odxrequire(self.dop)
@@ -48,23 +65,24 @@ class ValueParameter(ParameterWithDOP):
48
65
  return self._physical_default_value
49
66
 
50
67
  @property
68
+ @override
51
69
  def is_required(self) -> bool:
52
70
  return self._physical_default_value is None
53
71
 
54
72
  @property
73
+ @override
55
74
  def is_settable(self) -> bool:
56
75
  return True
57
76
 
58
- def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
59
- physical_value = encode_state.parameter_values.get(self.short_name,
60
- self.physical_default_value)
77
+ @override
78
+ def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
79
+ encode_state: EncodeState) -> None:
80
+
61
81
  if physical_value is None:
62
- raise TypeError(f"A value for parameter '{self.short_name}' must be specified"
63
- f" as the parameter does not exhibit a default.")
64
- dop = odxrequire(
65
- self.dop,
66
- f"Param {self.short_name} does not have a DOP. Maybe resolving references failed?")
67
-
68
- bit_position_int = self.bit_position if self.bit_position is not None else 0
69
- return dop.convert_physical_to_bytes(
70
- physical_value, encode_state=encode_state, bit_position=bit_position_int)
82
+ physical_value = self._physical_default_value
83
+ if physical_value is None:
84
+ odxraise(
85
+ f"A value for parameter '{self.short_name}' must be specified"
86
+ f" because the parameter does not exhibit a default.", EncodeError)
87
+
88
+ self.dop.encode_into_pdu(physical_value, encode_state=encode_state)
@@ -1,28 +1,46 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, cast
3
+ from typing import TYPE_CHECKING, Any, Dict, List, cast
4
+ from xml.etree import ElementTree
5
+
6
+ from typing_extensions import override
4
7
 
5
8
  from .decodestate import DecodeState
6
9
  from .diagcodedtype import DctType, DiagCodedType
7
10
  from .encodestate import EncodeState
8
- from .exceptions import odxraise
9
- from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
11
+ from .exceptions import EncodeError, odxraise, odxrequire
12
+ from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
10
13
  from .odxtypes import AtomicOdxType, DataType
14
+ from .snrefcontext import SnRefContext
15
+ from .utils import dataclass_fields_asdict
11
16
 
12
17
  if TYPE_CHECKING:
13
- from .diaglayer import DiagLayer
14
18
  from .parameters.lengthkeyparameter import LengthKeyParameter
15
19
 
16
20
 
17
21
  @dataclass
18
22
  class ParamLengthInfoType(DiagCodedType):
19
-
20
23
  length_key_ref: OdxLinkRef
21
24
 
22
25
  @property
23
26
  def dct_type(self) -> DctType:
24
27
  return "PARAM-LENGTH-INFO-TYPE"
25
28
 
29
+ @property
30
+ def length_key(self) -> "LengthKeyParameter":
31
+ return self._length_key
32
+
33
+ @staticmethod
34
+ @override
35
+ def from_et(et_element: ElementTree.Element,
36
+ doc_frags: List[OdxDocFragment]) -> "ParamLengthInfoType":
37
+ kwargs = dataclass_fields_asdict(DiagCodedType.from_et(et_element, doc_frags))
38
+
39
+ length_key_ref = odxrequire(
40
+ OdxLinkRef.from_et(et_element.find("LENGTH-KEY-REF"), doc_frags))
41
+
42
+ return ParamLengthInfoType(length_key_ref=length_key_ref, **kwargs)
43
+
26
44
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
27
45
  return super()._build_odxlinks()
28
46
 
@@ -30,45 +48,52 @@ class ParamLengthInfoType(DiagCodedType):
30
48
  """Recursively resolve any odxlinks references"""
31
49
  super()._resolve_odxlinks(odxlinks)
32
50
 
33
- self._length_key = odxlinks.resolve(self.length_key_ref)
51
+ if TYPE_CHECKING:
52
+ self._length_key = odxlinks.resolve(self.length_key_ref, LengthKeyParameter)
53
+ else:
54
+ self._length_key = odxlinks.resolve(self.length_key_ref)
34
55
 
35
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
56
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
36
57
  """Recursively resolve any short-name references"""
37
- super()._resolve_snrefs(diag_layer)
58
+ super()._resolve_snrefs(context)
38
59
 
39
- @property
40
- def length_key(self) -> "LengthKeyParameter":
41
- return self._length_key
42
-
43
- def convert_internal_to_bytes(self, internal_value: AtomicOdxType, encode_state: EncodeState,
44
- bit_position: int) -> bytes:
45
- bit_length = encode_state.parameter_values.get(self.length_key.short_name, None)
60
+ @override
61
+ def encode_into_pdu(self, internal_value: AtomicOdxType, encode_state: EncodeState) -> None:
62
+ bit_length = encode_state.length_keys.get(self.length_key.short_name)
46
63
 
47
64
  if bit_length is None:
65
+ # the length key is implicit, i.e., we need to set the
66
+ # value for the length key in the encode_state based on
67
+ # the value passed here.
48
68
  if self.base_data_type in [
49
69
  DataType.A_BYTEFIELD,
50
70
  DataType.A_ASCIISTRING,
51
71
  DataType.A_UTF8STRING,
52
72
  ]:
53
- bit_length = 8 * len(internal_value) # type: ignore[arg-type]
54
- if self.base_data_type in [DataType.A_UNICODE2STRING]:
55
- bit_length = 16 * len(internal_value) # type: ignore[arg-type]
56
-
57
- if self.base_data_type in [DataType.A_INT32, DataType.A_UINT32]:
73
+ bit_length = 8 * len(cast(str, internal_value))
74
+ elif self.base_data_type in [DataType.A_UNICODE2STRING]:
75
+ bit_length = 16 * len(cast(str, internal_value))
76
+ elif self.base_data_type in [DataType.A_INT32, DataType.A_UINT32]:
58
77
  bit_length = int(internal_value).bit_length()
59
78
  if self.base_data_type == DataType.A_INT32:
60
79
  bit_length += 1
61
80
  # Round up
62
81
  bit_length = ((bit_length + 7) // 8) * 8
63
-
64
- encode_state.parameter_values[self.length_key.short_name] = bit_length
65
-
66
- if bit_length is None:
67
- odxraise()
68
-
69
- return self._encode_internal_value(
70
- internal_value,
71
- bit_position=bit_position,
82
+ elif self.base_data_type == DataType.A_FLOAT32:
83
+ bit_length = 32
84
+ elif self.base_data_type == DataType.A_FLOAT64:
85
+ bit_length = 64
86
+ else:
87
+ odxraise(
88
+ f"Cannot determine size of an object of type "
89
+ f"{self.base_data_type.value}", EncodeError)
90
+ return
91
+
92
+ encode_state.length_keys[self.length_key.short_name] = bit_length
93
+
94
+ encode_state.emplace_atomic_value(
95
+ internal_value=internal_value,
96
+ used_mask=None,
72
97
  bit_length=bit_length,
73
98
  base_data_type=self.base_data_type,
74
99
  is_highlow_byte_order=self.is_highlow_byte_order,
@@ -79,7 +104,7 @@ class ParamLengthInfoType(DiagCodedType):
79
104
  if self.length_key.short_name not in decode_state.length_keys:
80
105
  odxraise(f"Unspecified mandatory length key parameter "
81
106
  f"{self.length_key.short_name}")
82
- decode_state.cursor_bit_position = None
107
+ decode_state.cursor_bit_position = 0
83
108
  return cast(None, AtomicOdxType)
84
109
 
85
110
  bit_length = decode_state.length_keys[self.length_key.short_name]
@@ -88,10 +113,8 @@ class ParamLengthInfoType(DiagCodedType):
88
113
  bit_length = 0
89
114
 
90
115
  # Extract the internal value and return.
91
- value = decode_state.extract_atomic_value(
116
+ return decode_state.extract_atomic_value(
92
117
  bit_length,
93
118
  self.base_data_type,
94
119
  self.is_highlow_byte_order,
95
120
  )
96
-
97
- return value
odxtools/parentref.py CHANGED
@@ -1,13 +1,16 @@
1
1
  # SPDX-License-Identifier: MIT
2
+ from copy import deepcopy
2
3
  from dataclasses import dataclass
3
4
  from typing import TYPE_CHECKING, Any, Dict, List
4
5
  from xml.etree import ElementTree
5
6
 
6
7
  from .exceptions import odxrequire
7
8
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
9
+ from .snrefcontext import SnRefContext
10
+ from .utils import dataclass_fields_asdict
8
11
 
9
12
  if TYPE_CHECKING:
10
- from .diaglayer import DiagLayer
13
+ from .diaglayers.diaglayer import DiagLayer
11
14
 
12
15
 
13
16
  @dataclass
@@ -71,7 +74,21 @@ class ParentRef:
71
74
  return {}
72
75
 
73
76
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
74
- self._layer = odxlinks.resolve(self.layer_ref)
77
+ if TYPE_CHECKING:
78
+ self._layer = odxlinks.resolve(self.layer_ref, DiagLayer)
79
+ else:
80
+ self._layer = odxlinks.resolve(self.layer_ref)
75
81
 
76
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
82
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
77
83
  pass
84
+
85
+ def __deepcopy__(self, memo: Dict[int, Any]) -> Any:
86
+ cls = self.__class__
87
+ result = cls.__new__(cls)
88
+ memo[id(self)] = result
89
+
90
+ fields = dataclass_fields_asdict(self)
91
+ for name, value in fields.items():
92
+ setattr(result, name, deepcopy(value))
93
+
94
+ return result
@@ -1,15 +1,13 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
3
+ from typing import Any, Dict, List
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import IdentifiableElement
7
7
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
8
+ from .snrefcontext import SnRefContext
8
9
  from .utils import dataclass_fields_asdict
9
10
 
10
- if TYPE_CHECKING:
11
- from .diaglayer import DiagLayer
12
-
13
11
 
14
12
  @dataclass
15
13
  class PhysicalDimension(IdentifiableElement):
@@ -43,7 +41,6 @@ class PhysicalDimension(IdentifiableElement):
43
41
  )
44
42
  ```
45
43
  """
46
- oid: Optional[str]
47
44
  length_exp: int
48
45
  mass_exp: int
49
46
  time_exp: int
@@ -56,7 +53,6 @@ class PhysicalDimension(IdentifiableElement):
56
53
  def from_et(et_element: ElementTree.Element,
57
54
  doc_frags: List[OdxDocFragment]) -> "PhysicalDimension":
58
55
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
59
- oid = et_element.get("OID")
60
56
 
61
57
  def read_optional_int(element: ElementTree.Element, name: str) -> int:
62
58
  if val_str := element.findtext(name):
@@ -73,7 +69,6 @@ class PhysicalDimension(IdentifiableElement):
73
69
  luminous_intensity_exp = read_optional_int(et_element, "LUMINOUS-INTENSITY-EXP")
74
70
 
75
71
  return PhysicalDimension(
76
- oid=oid,
77
72
  length_exp=length_exp,
78
73
  mass_exp=mass_exp,
79
74
  time_exp=time_exp,
@@ -89,5 +84,5 @@ class PhysicalDimension(IdentifiableElement):
89
84
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
90
85
  pass
91
86
 
92
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
87
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
93
88
  pass
odxtools/progcode.py CHANGED
@@ -1,25 +1,33 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
3
+ from typing import Any, Dict, List, Optional, cast
4
4
  from xml.etree import ElementTree
5
5
 
6
- from .exceptions import odxrequire
6
+ from .exceptions import odxraise, odxrequire
7
+ from .library import Library
8
+ from .nameditemlist import NamedItemList
7
9
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
8
-
9
- if TYPE_CHECKING:
10
- from .diaglayer import DiagLayer
10
+ from .snrefcontext import SnRefContext
11
11
 
12
12
 
13
13
  @dataclass
14
14
  class ProgCode:
15
15
  """A reference to code that is executed by a single ECU job"""
16
16
  code_file: str
17
+ encryption: Optional[str]
17
18
  syntax: str
18
19
  revision: str
19
- encryption: Optional[str]
20
20
  entrypoint: Optional[str]
21
21
  library_refs: List[OdxLinkRef]
22
22
 
23
+ @property
24
+ def code(self) -> bytes:
25
+ return self._code
26
+
27
+ @property
28
+ def libraries(self) -> NamedItemList[Library]:
29
+ return self._libraries
30
+
23
31
  @staticmethod
24
32
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "ProgCode":
25
33
  code_file = odxrequire(et_element.findtext("CODE-FILE"))
@@ -47,9 +55,16 @@ class ProgCode:
47
55
  return {}
48
56
 
49
57
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
50
- # TODO: Libraries are currently not internalized.
51
- # Once they are internalized, resolve the `library_refs` references here.
52
- pass
58
+ self._libraries = NamedItemList([odxlinks.resolve(x, Library) for x in self.library_refs])
59
+
60
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
61
+ aux_file = odxrequire(context.database).auxiliary_files.get(self.code_file)
62
+
63
+ if aux_file is None:
64
+ odxraise(f"Reference to auxiliary file '{self.code_file}' "
65
+ f"could not be resolved")
66
+ self._code: bytes = cast(bytes, None)
67
+ return
53
68
 
54
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
55
- pass
69
+ self._code = aux_file.read()
70
+ aux_file.seek(0)
odxtools/protstack.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List
3
+ from typing import Any, Dict, List
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .comparamsubset import ComparamSubset
@@ -8,11 +8,9 @@ from .element import IdentifiableElement
8
8
  from .exceptions import odxrequire
9
9
  from .nameditemlist import NamedItemList
10
10
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
11
+ from .snrefcontext import SnRefContext
11
12
  from .utils import dataclass_fields_asdict
12
13
 
13
- if TYPE_CHECKING:
14
- from .diaglayer import DiagLayer
15
-
16
14
 
17
15
  @dataclass
18
16
  class ProtStack(IdentifiableElement):
@@ -47,7 +45,7 @@ class ProtStack(IdentifiableElement):
47
45
  self._comparam_subsets = NamedItemList[ComparamSubset](
48
46
  [odxlinks.resolve(x, ComparamSubset) for x in self.comparam_subset_refs])
49
47
 
50
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
48
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
51
49
  pass
52
50
 
53
51
  @property
odxtools/py.typed ADDED
File without changes