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,36 +1,30 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from copy import copy
3
3
  from dataclasses import dataclass
4
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, cast
4
+ from typing import Any, Dict, List, Optional, Union, cast
5
5
  from xml.etree import ElementTree
6
6
 
7
- from .additionalaudience import AdditionalAudience
8
- from .admindata import AdminData
9
- from .companydata import CompanyData
10
- from .comparaminstance import ComparamInstance
11
- from .comparamspec import ComparamSpec
12
- from .createsdgs import create_sdgs_from_et
13
- from .diagcomm import DiagComm
14
- from .diagdatadictionaryspec import DiagDataDictionarySpec
7
+ from ..additionalaudience import AdditionalAudience
8
+ from ..admindata import AdminData
9
+ from ..companydata import CompanyData
10
+ from ..diagcomm import DiagComm
11
+ from ..diagdatadictionaryspec import DiagDataDictionarySpec
12
+ from ..diagservice import DiagService
13
+ from ..element import IdentifiableElement
14
+ from ..exceptions import odxassert, odxraise, odxrequire
15
+ from ..functionalclass import FunctionalClass
16
+ from ..library import Library
17
+ from ..nameditemlist import NamedItemList
18
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
19
+ from ..request import Request
20
+ from ..response import Response
21
+ from ..singleecujob import SingleEcuJob
22
+ from ..snrefcontext import SnRefContext
23
+ from ..specialdatagroup import SpecialDataGroup
24
+ from ..statechart import StateChart
25
+ from ..subcomponent import SubComponent
26
+ from ..utils import dataclass_fields_asdict
15
27
  from .diaglayertype import DiagLayerType
16
- from .diagservice import DiagService
17
- from .ecuvariantpattern import EcuVariantPattern
18
- from .element import IdentifiableElement
19
- from .exceptions import odxassert, odxraise, odxrequire
20
- from .functionalclass import FunctionalClass
21
- from .nameditemlist import NamedItemList
22
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
23
- from .parentref import ParentRef
24
- from .protstack import ProtStack
25
- from .request import Request
26
- from .response import Response
27
- from .singleecujob import SingleEcuJob
28
- from .specialdatagroup import SpecialDataGroup
29
- from .statechart import StateChart
30
- from .utils import dataclass_fields_asdict
31
-
32
- if TYPE_CHECKING:
33
- from .diaglayer import DiagLayer
34
28
 
35
29
 
36
30
  @dataclass
@@ -46,7 +40,7 @@ class DiagLayerRaw(IdentifiableElement):
46
40
  company_datas: NamedItemList[CompanyData]
47
41
  functional_classes: NamedItemList[FunctionalClass]
48
42
  diag_data_dictionary_spec: Optional[DiagDataDictionarySpec]
49
- diag_comms: List[Union[OdxLinkRef, DiagComm]]
43
+ diag_comms_raw: List[Union[OdxLinkRef, DiagComm]]
50
44
  requests: NamedItemList[Request]
51
45
  positive_responses: NamedItemList[Response]
52
46
  negative_responses: NamedItemList[Response]
@@ -54,21 +48,26 @@ class DiagLayerRaw(IdentifiableElement):
54
48
  import_refs: List[OdxLinkRef]
55
49
  state_charts: NamedItemList[StateChart]
56
50
  additional_audiences: NamedItemList[AdditionalAudience]
57
- # sub_components: List[DiagLayer] # TODO
58
- # libraries: List[DiagLayer] # TODO
51
+ sub_components: NamedItemList[SubComponent]
52
+ libraries: NamedItemList[Library]
59
53
  sdgs: List[SpecialDataGroup]
60
54
 
61
- # these attributes are only defined for some kinds of diag layers!
62
- # TODO: make a proper class hierarchy!
63
- parent_refs: List[ParentRef]
64
- comparams: List[ComparamInstance]
65
- ecu_variant_patterns: List[EcuVariantPattern]
66
- comparam_spec_ref: Optional[OdxLinkRef]
67
- prot_stack_snref: Optional[str]
68
- # diag_variables: List[DiagVariable] # TODO
69
- # diag_variable_groups: List[DiagVariableGroup] # TODO
70
- # dyn_defined_spec: Optional[DynDefinedSpec] # TODO
71
- # base_variant_patterns: List[EcuVariantPattern] # TODO
55
+ @property
56
+ def diag_comms(self) -> NamedItemList[DiagComm]:
57
+ return self._diag_comms
58
+
59
+ @property
60
+ def diag_services(self) -> NamedItemList[DiagService]:
61
+ return self._diag_services
62
+
63
+ @property
64
+ def services(self) -> NamedItemList[DiagService]:
65
+ """This property is an alias for `.diag_services`"""
66
+ return self._diag_services
67
+
68
+ @property
69
+ def single_ecu_jobs(self) -> NamedItemList[SingleEcuJob]:
70
+ return self._single_ecu_jobs
72
71
 
73
72
  @staticmethod
74
73
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DiagLayerRaw":
@@ -103,7 +102,7 @@ class DiagLayerRaw(IdentifiableElement):
103
102
  if (ddds_elem := et_element.find("DIAG-DATA-DICTIONARY-SPEC")) is not None:
104
103
  diag_data_dictionary_spec = DiagDataDictionarySpec.from_et(ddds_elem, doc_frags)
105
104
 
106
- diag_comms: List[Union[OdxLinkRef, DiagComm]] = []
105
+ diag_comms_raw: List[Union[OdxLinkRef, DiagComm]] = []
107
106
  if (dc_elems := et_element.find("DIAG-COMMS")) is not None:
108
107
  for dc_proxy_elem in dc_elems:
109
108
  dc: Union[OdxLinkRef, DiagComm]
@@ -115,7 +114,7 @@ class DiagLayerRaw(IdentifiableElement):
115
114
  odxassert(dc_proxy_elem.tag == "SINGLE-ECU-JOB")
116
115
  dc = SingleEcuJob.from_et(dc_proxy_elem, doc_frags)
117
116
 
118
- diag_comms.append(dc)
117
+ diag_comms_raw.append(dc)
119
118
 
120
119
  requests = NamedItemList([
121
120
  Request.from_et(rq_elem, doc_frags)
@@ -152,31 +151,18 @@ class DiagLayerRaw(IdentifiableElement):
152
151
  for el in et_element.iterfind("ADDITIONAL-AUDIENCES/ADDITIONAL-AUDIENCE")
153
152
  ]
154
153
 
155
- sdgs = create_sdgs_from_et(et_element.find("SDGS"), doc_frags)
156
-
157
- parent_refs = [
158
- ParentRef.from_et(pr_el, doc_frags)
159
- for pr_el in et_element.iterfind("PARENT-REFS/PARENT-REF")
154
+ libraries = [
155
+ Library.from_et(el, doc_frags) for el in et_element.iterfind("LIBRARYS/LIBRARY")
160
156
  ]
161
157
 
162
- comparams = [
163
- ComparamInstance.from_et(el, doc_frags)
164
- for el in et_element.iterfind("COMPARAM-REFS/COMPARAM-REF")
158
+ sub_components = [
159
+ SubComponent.from_et(el, doc_frags)
160
+ for el in et_element.iterfind("SUB-COMPONENTS/SUB-COMPONENT")
165
161
  ]
166
162
 
167
- ecu_variant_patterns = [
168
- EcuVariantPattern.from_et(el, doc_frags)
169
- for el in et_element.iterfind("ECU-VARIANT-PATTERNS/ECU-VARIANT-PATTERN")
163
+ sdgs = [
164
+ SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
170
165
  ]
171
- if variant_type is not DiagLayerType.ECU_VARIANT:
172
- odxassert(
173
- len(ecu_variant_patterns) == 0,
174
- "DiagLayer of type other than 'ECU-VARIANT' must not define a ECU-VARIANT-PATTERN")
175
-
176
- comparam_spec_ref = OdxLinkRef.from_et(et_element.find("COMPARAM-SPEC-REF"), doc_frags)
177
- prot_stack_snref: Optional[str] = None
178
- if (prot_stack_snref_elem := et_element.find("PROT-STACK-SNREF")) is not None:
179
- prot_stack_snref = odxrequire(prot_stack_snref_elem.get("SHORT-NAME"))
180
166
 
181
167
  # Create DiagLayer
182
168
  return DiagLayerRaw(
@@ -185,7 +171,7 @@ class DiagLayerRaw(IdentifiableElement):
185
171
  company_datas=NamedItemList(company_datas),
186
172
  functional_classes=NamedItemList(functional_classes),
187
173
  diag_data_dictionary_spec=diag_data_dictionary_spec,
188
- diag_comms=diag_comms,
174
+ diag_comms_raw=diag_comms_raw,
189
175
  requests=requests,
190
176
  positive_responses=positive_responses,
191
177
  negative_responses=negative_responses,
@@ -193,12 +179,9 @@ class DiagLayerRaw(IdentifiableElement):
193
179
  import_refs=import_refs,
194
180
  state_charts=NamedItemList(state_charts),
195
181
  additional_audiences=NamedItemList(additional_audiences),
182
+ libraries=NamedItemList(libraries),
183
+ sub_components=NamedItemList(sub_components),
196
184
  sdgs=sdgs,
197
- parent_refs=parent_refs,
198
- comparams=comparams,
199
- ecu_variant_patterns=ecu_variant_patterns,
200
- comparam_spec_ref=comparam_spec_ref,
201
- prot_stack_snref=prot_stack_snref,
202
185
  **kwargs)
203
186
 
204
187
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
@@ -214,10 +197,10 @@ class DiagLayerRaw(IdentifiableElement):
214
197
  odxlinks.update(company_data._build_odxlinks())
215
198
  for functional_class in self.functional_classes:
216
199
  odxlinks.update(functional_class._build_odxlinks())
217
- for diag_comm in self.diag_comms:
218
- if isinstance(diag_comm, OdxLinkRef):
200
+ for dc_proxy in self.diag_comms_raw:
201
+ if isinstance(dc_proxy, OdxLinkRef):
219
202
  continue
220
- odxlinks.update(diag_comm._build_odxlinks())
203
+ odxlinks.update(dc_proxy._build_odxlinks())
221
204
  for request in self.requests:
222
205
  odxlinks.update(request._build_odxlinks())
223
206
  for positive_response in self.positive_responses:
@@ -230,21 +213,18 @@ class DiagLayerRaw(IdentifiableElement):
230
213
  odxlinks.update(state_chart._build_odxlinks())
231
214
  for additional_audience in self.additional_audiences:
232
215
  odxlinks.update(additional_audience._build_odxlinks())
216
+ for library in self.libraries:
217
+ odxlinks.update(library._build_odxlinks())
218
+ for sub_comp in self.sub_components:
219
+ odxlinks.update(sub_comp._build_odxlinks())
233
220
  for sdg in self.sdgs:
234
221
  odxlinks.update(sdg._build_odxlinks())
235
- for parent_ref in self.parent_refs:
236
- odxlinks.update(parent_ref._build_odxlinks())
237
- for comparam in self.comparams:
238
- odxlinks.update(comparam._build_odxlinks())
239
222
 
240
223
  return odxlinks
241
224
 
242
225
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
243
226
  """Recursively resolve all references."""
244
227
 
245
- if self.comparam_spec_ref is not None:
246
- self._comparam_spec = odxlinks.resolve(self.comparam_spec_ref, ComparamSpec)
247
-
248
228
  # do ODXLINK reference resolution
249
229
  if self.admin_data is not None:
250
230
  self.admin_data._resolve_odxlinks(odxlinks)
@@ -255,10 +235,28 @@ class DiagLayerRaw(IdentifiableElement):
255
235
  company_data._resolve_odxlinks(odxlinks)
256
236
  for functional_class in self.functional_classes:
257
237
  functional_class._resolve_odxlinks(odxlinks)
258
- for diag_comm in self.diag_comms:
259
- if isinstance(diag_comm, OdxLinkRef):
260
- continue
261
- diag_comm._resolve_odxlinks(odxlinks)
238
+
239
+ # resolve references to diagnostic communication objects and
240
+ # separate them into services and single-ecu jobs
241
+ self._diag_comms = NamedItemList[DiagComm]()
242
+ self._diag_services = NamedItemList[DiagService]()
243
+ self._single_ecu_jobs = NamedItemList[SingleEcuJob]()
244
+ for dc_proxy in self.diag_comms_raw:
245
+ if isinstance(dc_proxy, OdxLinkRef):
246
+ dc = odxlinks.resolve(dc_proxy, DiagComm)
247
+ else:
248
+ dc = dc_proxy
249
+ dc._resolve_odxlinks(odxlinks)
250
+
251
+ self._diag_comms.append(dc)
252
+
253
+ if isinstance(dc, DiagService):
254
+ self._diag_services.append(dc)
255
+ elif isinstance(dc, SingleEcuJob):
256
+ self._single_ecu_jobs.append(dc)
257
+ else:
258
+ odxraise()
259
+
262
260
  for request in self.requests:
263
261
  request._resolve_odxlinks(odxlinks)
264
262
  for positive_response in self.positive_responses:
@@ -271,56 +269,43 @@ class DiagLayerRaw(IdentifiableElement):
271
269
  state_chart._resolve_odxlinks(odxlinks)
272
270
  for additional_audience in self.additional_audiences:
273
271
  additional_audience._resolve_odxlinks(odxlinks)
272
+ for library in self.libraries:
273
+ library._resolve_odxlinks(odxlinks)
274
+ for sub_component in self.sub_components:
275
+ sub_component._resolve_odxlinks(odxlinks)
274
276
  for sdg in self.sdgs:
275
277
  sdg._resolve_odxlinks(odxlinks)
276
- for parent_ref in self.parent_refs:
277
- parent_ref._resolve_odxlinks(odxlinks)
278
- for comparam in self.comparams:
279
- comparam._resolve_odxlinks(odxlinks)
280
-
281
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
282
- self._prot_stack: Optional[ProtStack] = None
283
- if self.prot_stack_snref is not None:
284
- self._prot_stack = odxrequire(
285
- odxrequire(self.comparam_spec).prot_stacks.get(self.prot_stack_snref))
286
278
 
279
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
287
280
  # do short-name reference resolution
288
281
  if self.admin_data is not None:
289
- self.admin_data._resolve_snrefs(diag_layer)
282
+ self.admin_data._resolve_snrefs(context)
290
283
  if self.diag_data_dictionary_spec is not None:
291
- self.diag_data_dictionary_spec._resolve_snrefs(diag_layer)
284
+ self.diag_data_dictionary_spec._resolve_snrefs(context)
292
285
 
293
286
  for company_data in self.company_datas:
294
- company_data._resolve_snrefs(diag_layer)
295
- for functional_classe in self.functional_classes:
296
- functional_classe._resolve_snrefs(diag_layer)
297
- for diag_comm in self.diag_comms:
298
- if isinstance(diag_comm, OdxLinkRef):
287
+ company_data._resolve_snrefs(context)
288
+ for functional_class in self.functional_classes:
289
+ functional_class._resolve_snrefs(context)
290
+ for dc_proxy in self.diag_comms_raw:
291
+ if isinstance(dc_proxy, OdxLinkRef):
299
292
  continue
300
- diag_comm._resolve_snrefs(diag_layer)
293
+ dc_proxy._resolve_snrefs(context)
301
294
  for request in self.requests:
302
- request._resolve_snrefs(diag_layer)
295
+ request._resolve_snrefs(context)
303
296
  for positive_response in self.positive_responses:
304
- positive_response._resolve_snrefs(diag_layer)
297
+ positive_response._resolve_snrefs(context)
305
298
  for negative_response in self.negative_responses:
306
- negative_response._resolve_snrefs(diag_layer)
299
+ negative_response._resolve_snrefs(context)
307
300
  for global_negative_response in self.global_negative_responses:
308
- global_negative_response._resolve_snrefs(diag_layer)
301
+ global_negative_response._resolve_snrefs(context)
309
302
  for state_chart in self.state_charts:
310
- state_chart._resolve_snrefs(diag_layer)
303
+ state_chart._resolve_snrefs(context)
311
304
  for additional_audience in self.additional_audiences:
312
- additional_audience._resolve_snrefs(diag_layer)
305
+ additional_audience._resolve_snrefs(context)
306
+ for library in self.libraries:
307
+ library._resolve_snrefs(context)
308
+ for sub_component in self.sub_components:
309
+ sub_component._resolve_snrefs(context)
313
310
  for sdg in self.sdgs:
314
- sdg._resolve_snrefs(diag_layer)
315
- for parent_ref in self.parent_refs:
316
- parent_ref._resolve_snrefs(diag_layer)
317
- for comparam in self.comparams:
318
- comparam._resolve_snrefs(diag_layer)
319
-
320
- @property
321
- def comparam_spec(self) -> Optional[ComparamSpec]:
322
- return self._comparam_spec
323
-
324
- @property
325
- def prot_stack(self) -> Optional[ProtStack]:
326
- return self._prot_stack
311
+ sdg._resolve_snrefs(context)
@@ -0,0 +1,42 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from enum import Enum
3
+ from typing import Dict
4
+
5
+
6
+ class DiagLayerType(Enum):
7
+ PROTOCOL = "PROTOCOL"
8
+ FUNCTIONAL_GROUP = "FUNCTIONAL-GROUP"
9
+ BASE_VARIANT = "BASE-VARIANT"
10
+ ECU_VARIANT = "ECU-VARIANT"
11
+ ECU_SHARED_DATA = "ECU-SHARED-DATA"
12
+
13
+ @property
14
+ def inheritance_priority(self) -> int:
15
+ """Return the inheritance priority of diag layers of the given type
16
+
17
+ ODX mandates that diagnostic layers can only inherit from
18
+ layers of lower priority...
19
+
20
+ """
21
+
22
+ PRIORITY_OF_DIAG_LAYER_TYPE: Dict[DiagLayerType, int] = {
23
+ DiagLayerType.PROTOCOL:
24
+ 1,
25
+ DiagLayerType.FUNCTIONAL_GROUP:
26
+ 2,
27
+ DiagLayerType.BASE_VARIANT:
28
+ 3,
29
+ DiagLayerType.ECU_VARIANT:
30
+ 4,
31
+
32
+ # ECU shared data layers are a bit weird (see section
33
+ # 7.3.2.4.4 of the ASAM specification): they can be
34
+ # inherited from by any other layer but they will
35
+ # override any objects which are also provided by any of
36
+ # the other parent layers. tl;dr: When it comes to
37
+ # inheritance, they have the highest priority.
38
+ DiagLayerType.ECU_SHARED_DATA:
39
+ 100,
40
+ }
41
+
42
+ return PRIORITY_OF_DIAG_LAYER_TYPE[self]
@@ -0,0 +1,96 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from copy import deepcopy
3
+ from dataclasses import dataclass
4
+ from typing import TYPE_CHECKING, Any, Dict, List, Union, cast
5
+ from xml.etree import ElementTree
6
+
7
+ from ..diagvariable import DiagVariable
8
+ from ..exceptions import odxassert
9
+ from ..nameditemlist import NamedItemList
10
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkRef
11
+ from ..snrefcontext import SnRefContext
12
+ from ..variablegroup import VariableGroup
13
+ from .diaglayer import DiagLayer
14
+ from .ecushareddataraw import EcuSharedDataRaw
15
+
16
+ if TYPE_CHECKING:
17
+ from .database import Database
18
+
19
+
20
+ @dataclass
21
+ class EcuSharedData(DiagLayer):
22
+ """This is a diagnostic layer for data shared across others
23
+ """
24
+
25
+ @property
26
+ def ecu_shared_data_raw(self) -> EcuSharedDataRaw:
27
+ return cast(EcuSharedDataRaw, self.diag_layer_raw)
28
+
29
+ @property
30
+ def diag_variables_raw(self) -> List[Union[OdxLinkRef, DiagVariable]]:
31
+ return self.ecu_shared_data_raw.diag_variables_raw
32
+
33
+ @property
34
+ def diag_variables(self) -> NamedItemList[DiagVariable]:
35
+ return self.ecu_shared_data_raw.diag_variables
36
+
37
+ @property
38
+ def variable_groups(self) -> NamedItemList[VariableGroup]:
39
+ return self.ecu_shared_data_raw.variable_groups
40
+
41
+ @staticmethod
42
+ def from_et(et_element: ElementTree.Element,
43
+ doc_frags: List[OdxDocFragment]) -> "EcuSharedData":
44
+ ecu_shared_data_raw = EcuSharedDataRaw.from_et(et_element, doc_frags)
45
+
46
+ return EcuSharedData(diag_layer_raw=ecu_shared_data_raw)
47
+
48
+ def __post_init__(self) -> None:
49
+ super().__post_init__()
50
+
51
+ odxassert(
52
+ isinstance(self.diag_layer_raw, EcuSharedDataRaw),
53
+ "The raw diagnostic layer passed to EcuSharedData "
54
+ "must be a EcuSharedDataRaw")
55
+
56
+ def _finalize_init(self, database: "Database", odxlinks: OdxLinkDatabase) -> None:
57
+ """This method makes sure that all references in sub-objects
58
+ of the ECU shared data layer are resolved
59
+
60
+ In contrast to hierarchy element layers, ECU shared data
61
+ layers do not need to deal with inheritance...
62
+
63
+ """
64
+
65
+ # this attribute may be removed later. it is currently
66
+ # required to properly deal with auxiliary files within the
67
+ # diagnostic layer.
68
+ self._database = database
69
+
70
+ #####
71
+ # resolve all SNREFs. TODO: We allow SNREFS to objects that
72
+ # were inherited by the diaglayer. This might not be allowed
73
+ # by the spec (So far, I haven't found any definitive
74
+ # statement...)
75
+ #####
76
+ context = SnRefContext(database=database)
77
+ context.diag_layer = self
78
+ self._resolve_snrefs(context)
79
+ context.diag_layer = None
80
+
81
+ def __deepcopy__(self, memo: Dict[int, Any]) -> Any:
82
+ """Create a deep copy of the protocol layer
83
+
84
+ Note that the copied diagnostic layer is not fully
85
+ initialized, so `_finalize_init()` should to be called on it
86
+ before it can be used normally.
87
+ """
88
+
89
+ result = super().__deepcopy__(memo)
90
+
91
+ # note that the self.ecu_shared_data_raw object is *not* copied at
92
+ # this place because the attribute points to the same object
93
+ # as self.diag_layer_raw.
94
+ result.ecu_shared_data_raw = deepcopy(self.ecu_shared_data_raw, memo)
95
+
96
+ return result
@@ -0,0 +1,87 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import Any, Dict, List, Union
4
+ from xml.etree import ElementTree
5
+
6
+ from ..diagvariable import DiagVariable
7
+ from ..exceptions import odxraise
8
+ from ..nameditemlist import NamedItemList
9
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
10
+ from ..snrefcontext import SnRefContext
11
+ from ..utils import dataclass_fields_asdict
12
+ from ..variablegroup import VariableGroup
13
+ from .diaglayerraw import DiagLayerRaw
14
+
15
+
16
+ @dataclass
17
+ class EcuSharedDataRaw(DiagLayerRaw):
18
+ """This is a diagnostic layer for data shared accross others
19
+ """
20
+
21
+ diag_variables_raw: List[Union[DiagVariable, OdxLinkRef]]
22
+ variable_groups: NamedItemList[VariableGroup]
23
+
24
+ @property
25
+ def diag_variables(self) -> NamedItemList[DiagVariable]:
26
+ return self._diag_variables
27
+
28
+ @staticmethod
29
+ def from_et(et_element: ElementTree.Element,
30
+ doc_frags: List[OdxDocFragment]) -> "EcuSharedDataRaw":
31
+ # objects contained by diagnostic layers exibit an additional
32
+ # document fragment for the diag layer, so we use the document
33
+ # fragments of the odx id of the diag layer for IDs of
34
+ # contained objects.
35
+ dlr = DiagLayerRaw.from_et(et_element, doc_frags)
36
+ kwargs = dataclass_fields_asdict(dlr)
37
+ doc_frags = dlr.odx_id.doc_fragments
38
+
39
+ diag_variables_raw: List[Union[DiagVariable, OdxLinkRef]] = []
40
+ if (dv_elems := et_element.find("DIAG-VARIABLES")) is not None:
41
+ for dv_proxy_elem in dv_elems:
42
+ dv_proxy: Union[OdxLinkRef, DiagVariable]
43
+ if dv_proxy_elem.tag == "DIAG-VARIABLE-REF":
44
+ dv_proxy = OdxLinkRef.from_et(dv_proxy_elem, doc_frags)
45
+ elif dv_proxy_elem.tag == "DIAG-VARIABLE":
46
+ dv_proxy = DiagVariable.from_et(dv_proxy_elem, doc_frags)
47
+ else:
48
+ odxraise()
49
+
50
+ diag_variables_raw.append(dv_proxy)
51
+
52
+ variable_groups = NamedItemList([
53
+ VariableGroup.from_et(vg_elem, doc_frags)
54
+ for vg_elem in et_element.iterfind("VARIABLE-GROUPS/VARIABLE-GROUP")
55
+ ])
56
+
57
+ # Create DiagLayer
58
+ return EcuSharedDataRaw(
59
+ diag_variables_raw=diag_variables_raw, variable_groups=variable_groups, **kwargs)
60
+
61
+ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
62
+ result = super()._build_odxlinks()
63
+ for dv_proxy in self.diag_variables_raw:
64
+ if not isinstance(dv_proxy, OdxLinkRef):
65
+ result.update(dv_proxy._build_odxlinks())
66
+
67
+ return result
68
+
69
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
70
+ super()._resolve_odxlinks(odxlinks)
71
+
72
+ self._diag_variables: NamedItemList[DiagVariable] = NamedItemList()
73
+ for dv_proxy in self.diag_variables_raw:
74
+ if isinstance(dv_proxy, OdxLinkRef):
75
+ dv = odxlinks.resolve(dv_proxy, DiagVariable)
76
+ else:
77
+ dv_proxy._resolve_odxlinks(odxlinks)
78
+ dv = dv_proxy
79
+
80
+ self._diag_variables.append(dv)
81
+
82
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
83
+ super()._resolve_snrefs(context)
84
+
85
+ for dv_proxy in self.diag_variables_raw:
86
+ if not isinstance(dv_proxy, OdxLinkRef):
87
+ dv_proxy._resolve_snrefs(context)