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
odxtools/relateddoc.py CHANGED
@@ -1,24 +1,22 @@
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
4
4
  from xml.etree import ElementTree
5
5
 
6
+ from .description import Description
6
7
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
7
- from .utils import create_description_from_et
8
+ from .snrefcontext import SnRefContext
8
9
  from .xdoc import XDoc
9
10
 
10
- if TYPE_CHECKING:
11
- from .diaglayer import DiagLayer
12
-
13
11
 
14
12
  @dataclass
15
13
  class RelatedDoc:
16
- description: Optional[str]
14
+ description: Optional[Description]
17
15
  xdoc: Optional[XDoc]
18
16
 
19
17
  @staticmethod
20
18
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "RelatedDoc":
21
- description = create_description_from_et(et_element.find("DESC"))
19
+ description = Description.from_et(et_element.find("DESC"), doc_frags)
22
20
 
23
21
  xdoc: Optional[XDoc] = None
24
22
  if (xdoc_elem := et_element.find("XDOC")) is not None:
@@ -41,6 +39,6 @@ class RelatedDoc:
41
39
  if self.xdoc:
42
40
  self.xdoc._resolve_odxlinks(odxlinks)
43
41
 
44
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
42
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
45
43
  if self.xdoc:
46
- self.xdoc._resolve_snrefs(diag_layer)
44
+ self.xdoc._resolve_snrefs(context)
odxtools/request.py CHANGED
@@ -1,22 +1,132 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import List
3
+ from typing import Any, Dict, List, Optional, cast
4
4
  from xml.etree import ElementTree
5
5
 
6
- from .basicstructure import BasicStructure
7
- from .odxlink import OdxDocFragment
6
+ from .admindata import AdminData
7
+ from .codec import (composite_codec_decode_from_pdu, composite_codec_encode_into_pdu,
8
+ composite_codec_get_coded_const_prefix, composite_codec_get_free_parameters,
9
+ composite_codec_get_required_parameters, composite_codec_get_static_bit_length)
10
+ from .decodestate import DecodeState
11
+ from .element import IdentifiableElement
12
+ from .encodestate import EncodeState
13
+ from .exceptions import odxraise
14
+ from .nameditemlist import NamedItemList
15
+ from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
16
+ from .odxtypes import ParameterValue, ParameterValueDict
17
+ from .parameters.createanyparameter import create_any_parameter_from_et
18
+ from .parameters.parameter import Parameter
19
+ from .snrefcontext import SnRefContext
20
+ from .specialdatagroup import SpecialDataGroup
8
21
  from .utils import dataclass_fields_asdict
9
22
 
10
23
 
11
- # TODO: The spec does not say that requests are basic structures. For
12
- # now, we derive from it anyway because it simplifies the en- and
13
- # decoding machinery...
14
24
  @dataclass
15
- class Request(BasicStructure):
25
+ class Request(IdentifiableElement):
26
+ """Represents all information related to an UDS request
27
+
28
+ This class implements the `CompositeCodec` interface.
29
+ """
30
+ admin_data: Optional[AdminData]
31
+ parameters: NamedItemList[Parameter]
32
+ sdgs: List[SpecialDataGroup]
33
+
34
+ @property
35
+ def required_parameters(self) -> List[Parameter]:
36
+ return composite_codec_get_required_parameters(self)
37
+
38
+ @property
39
+ def free_parameters(self) -> List[Parameter]:
40
+ return composite_codec_get_free_parameters(self)
16
41
 
17
42
  @staticmethod
18
43
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Request":
19
- """Reads a response."""
20
- kwargs = dataclass_fields_asdict(BasicStructure.from_et(et_element, doc_frags))
44
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
45
+
46
+ admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
47
+ parameters = NamedItemList([
48
+ create_any_parameter_from_et(et_parameter, doc_frags)
49
+ for et_parameter in et_element.iterfind("PARAMS/PARAM")
50
+ ])
51
+ sdgs = [
52
+ SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
53
+ ]
54
+
55
+ return Request(admin_data=admin_data, parameters=parameters, sdgs=sdgs, **kwargs)
56
+
57
+ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
58
+ result = {self.odx_id: self}
59
+
60
+ if self.admin_data is not None:
61
+ result.update(self.admin_data._build_odxlinks())
62
+
63
+ for param in self.parameters:
64
+ result.update(param._build_odxlinks())
65
+
66
+ for sdg in self.sdgs:
67
+ result.update(sdg._build_odxlinks())
68
+
69
+ return result
70
+
71
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
72
+ if self.admin_data is not None:
73
+ self.admin_data._resolve_odxlinks(odxlinks)
74
+
75
+ for param in self.parameters:
76
+ param._resolve_odxlinks(odxlinks)
77
+
78
+ for sdg in self.sdgs:
79
+ sdg._resolve_odxlinks(odxlinks)
80
+
81
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
82
+ context.request = self
83
+ context.parameters = self.parameters
84
+
85
+ if self.admin_data is not None:
86
+ self.admin_data._resolve_snrefs(context)
87
+
88
+ for param in self.parameters:
89
+ param._resolve_snrefs(context)
90
+
91
+ for sdg in self.sdgs:
92
+ sdg._resolve_snrefs(context)
93
+
94
+ context.request = None
95
+ context.parameters = None
96
+
97
+ def get_static_bit_length(self) -> Optional[int]:
98
+ return composite_codec_get_static_bit_length(self)
99
+
100
+ def print_free_parameters_info(self) -> None:
101
+ """Print a human readable description of the composite codec's
102
+ free parameters to `stdout`
103
+ """
104
+ from .parameterinfo import parameter_info
105
+
106
+ print(parameter_info(self.free_parameters), end="")
107
+
108
+ def encode(self, **kwargs: ParameterValue) -> bytearray:
109
+ encode_state = EncodeState(is_end_of_pdu=True)
110
+
111
+ self.encode_into_pdu(physical_value=kwargs, encode_state=encode_state)
112
+
113
+ return encode_state.coded_message
114
+
115
+ def decode(self, message: bytes) -> ParameterValueDict:
116
+ decode_state = DecodeState(coded_message=message)
117
+ param_values = self.decode_from_pdu(decode_state)
118
+
119
+ if not isinstance(param_values, dict):
120
+ odxraise("Decoding a request must result in a dictionary")
121
+
122
+ return cast(ParameterValueDict, param_values)
123
+
124
+ def encode_into_pdu(self, physical_value: Optional[ParameterValue],
125
+ encode_state: EncodeState) -> None:
126
+ composite_codec_encode_into_pdu(self, physical_value, encode_state)
127
+
128
+ def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
129
+ return composite_codec_decode_from_pdu(self, decode_state)
21
130
 
22
- return Request(**kwargs)
131
+ def coded_const_prefix(self, request_prefix: bytes = b'') -> bytes:
132
+ return composite_codec_get_coded_const_prefix(self, request_prefix)
odxtools/response.py CHANGED
@@ -1,14 +1,24 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
3
  from enum import Enum
4
- from typing import List, Optional, cast
4
+ from typing import Any, Dict, List, Optional, cast
5
5
  from xml.etree import ElementTree
6
6
 
7
- from .basicstructure import BasicStructure
7
+ from .admindata import AdminData
8
+ from .codec import (composite_codec_decode_from_pdu, composite_codec_encode_into_pdu,
9
+ composite_codec_get_coded_const_prefix, composite_codec_get_free_parameters,
10
+ composite_codec_get_required_parameters, composite_codec_get_static_bit_length)
11
+ from .decodestate import DecodeState
12
+ from .element import IdentifiableElement
13
+ from .encodestate import EncodeState
8
14
  from .exceptions import odxraise
9
- from .odxlink import OdxDocFragment
10
- from .odxtypes import ParameterValue
11
- from .parameters.matchingrequestparameter import MatchingRequestParameter
15
+ from .nameditemlist import NamedItemList
16
+ from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
17
+ from .odxtypes import ParameterValue, ParameterValueDict
18
+ from .parameters.createanyparameter import create_any_parameter_from_et
19
+ from .parameters.parameter import Parameter
20
+ from .snrefcontext import SnRefContext
21
+ from .specialdatagroup import SpecialDataGroup
12
22
  from .utils import dataclass_fields_asdict
13
23
 
14
24
 
@@ -18,17 +28,23 @@ class ResponseType(Enum):
18
28
  GLOBAL_NEGATIVE = "GLOBAL-NEG-RESPONSE"
19
29
 
20
30
 
21
- # TODO: The spec does not say that responses are basic structures. For
22
- # now, we derive from it anyway because it simplifies the en- and
23
- # decoding machinery...
24
31
  @dataclass
25
- class Response(BasicStructure):
32
+ class Response(IdentifiableElement):
33
+ """Represents all information related to an UDS response
34
+
35
+ This class implements the `CompositeCodec` interface.
36
+ """
37
+
26
38
  response_type: ResponseType
27
39
 
40
+ admin_data: Optional[AdminData]
41
+ parameters: NamedItemList[Parameter]
42
+ sdgs: List[SpecialDataGroup]
43
+
28
44
  @staticmethod
29
45
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Response":
30
46
  """Reads a response."""
31
- kwargs = dataclass_fields_asdict(BasicStructure.from_et(et_element, doc_frags))
47
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
32
48
 
33
49
  try:
34
50
  response_type = ResponseType(et_element.tag)
@@ -36,19 +52,103 @@ class Response(BasicStructure):
36
52
  response_type = cast(ResponseType, None)
37
53
  odxraise(f"Encountered unknown response type '{et_element.tag}'")
38
54
 
39
- return Response(response_type=response_type, **kwargs)
55
+ admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
56
+ parameters = NamedItemList([
57
+ create_any_parameter_from_et(et_parameter, doc_frags)
58
+ for et_parameter in et_element.iterfind("PARAMS/PARAM")
59
+ ])
60
+ sdgs = [
61
+ SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
62
+ ]
63
+
64
+ return Response(
65
+ response_type=response_type,
66
+ admin_data=admin_data,
67
+ parameters=parameters,
68
+ sdgs=sdgs,
69
+ **kwargs)
70
+
71
+ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
72
+ result = {self.odx_id: self}
73
+
74
+ if self.admin_data is not None:
75
+ result.update(self.admin_data._build_odxlinks())
76
+
77
+ for param in self.parameters:
78
+ result.update(param._build_odxlinks())
79
+
80
+ for sdg in self.sdgs:
81
+ result.update(sdg._build_odxlinks())
82
+
83
+ return result
84
+
85
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
86
+ if self.admin_data is not None:
87
+ self.admin_data._resolve_odxlinks(odxlinks)
88
+
89
+ for param in self.parameters:
90
+ param._resolve_odxlinks(odxlinks)
91
+
92
+ for sdg in self.sdgs:
93
+ sdg._resolve_odxlinks(odxlinks)
94
+
95
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
96
+ context.response = self
97
+ context.parameters = self.parameters
98
+
99
+ if self.admin_data is not None:
100
+ self.admin_data._resolve_snrefs(context)
101
+
102
+ for param in self.parameters:
103
+ param._resolve_snrefs(context)
104
+
105
+ for sdg in self.sdgs:
106
+ sdg._resolve_snrefs(context)
107
+
108
+ context.response = None
109
+ context.parameters = None
110
+
111
+ def encode(self, coded_request: Optional[bytes] = None, **kwargs: ParameterValue) -> bytearray:
112
+ encode_state = EncodeState(triggering_request=coded_request, is_end_of_pdu=True)
113
+
114
+ self.encode_into_pdu(physical_value=kwargs, encode_state=encode_state)
115
+
116
+ return encode_state.coded_message
117
+
118
+ def decode(self, message: bytes) -> ParameterValueDict:
119
+ decode_state = DecodeState(coded_message=message)
120
+ param_values = self.decode_from_pdu(decode_state)
121
+
122
+ if not isinstance(param_values, dict):
123
+ odxraise("Decoding a response must result in a dictionary")
124
+
125
+ return cast(ParameterValueDict, param_values)
126
+
127
+ def encode_into_pdu(self, physical_value: Optional[ParameterValue],
128
+ encode_state: EncodeState) -> None:
129
+ composite_codec_encode_into_pdu(self, physical_value, encode_state)
130
+
131
+ def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
132
+ return composite_codec_decode_from_pdu(self, decode_state)
133
+
134
+ def get_static_bit_length(self) -> Optional[int]:
135
+ return composite_codec_get_static_bit_length(self)
136
+
137
+ @property
138
+ def required_parameters(self) -> List[Parameter]:
139
+ return composite_codec_get_required_parameters(self)
140
+
141
+ @property
142
+ def free_parameters(self) -> List[Parameter]:
143
+ return composite_codec_get_free_parameters(self)
40
144
 
41
- def encode(self, coded_request: Optional[bytes] = None, **params: ParameterValue) -> bytes:
42
- if coded_request is not None:
43
- # Extract MATCHING-REQUEST-PARAMs from the coded
44
- # request. TODO: this should be done by
45
- # MatchingRequestParam itself!
46
- for param in self.parameters:
47
- if isinstance(param, MatchingRequestParameter):
48
- byte_pos = param.request_byte_position
49
- byte_length = param.byte_length
145
+ def print_free_parameters_info(self) -> None:
146
+ """Return a human readable description of the structure's
147
+ free parameters.
148
+ """
149
+ from .parameterinfo import parameter_info
50
150
 
51
- val = coded_request[byte_pos:byte_pos + byte_length]
52
- params[param.short_name] = val
151
+ print(parameter_info(self.free_parameters), end="")
53
152
 
54
- return super().encode(coded_request=coded_request, **params)
153
+ def coded_const_prefix(self, request_prefix: bytes = b'') -> bytes:
154
+ return composite_codec_get_coded_const_prefix(self, request_prefix)
odxtools/scaleconstr.py CHANGED
@@ -1,13 +1,14 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
3
  from enum import Enum
4
- from typing import Optional
4
+ from typing import List, Optional
5
5
  from xml.etree import ElementTree
6
6
 
7
7
  from .compumethods.limit import Limit
8
+ from .description import Description
8
9
  from .exceptions import odxraise, odxrequire
10
+ from .odxlink import OdxDocFragment
9
11
  from .odxtypes import DataType
10
- from .utils import create_description_from_et
11
12
 
12
13
 
13
14
  class ValidType(Enum):
@@ -23,18 +24,22 @@ class ScaleConstr:
23
24
  """
24
25
 
25
26
  short_label: Optional[str]
26
- description: Optional[str]
27
+ description: Optional[Description]
27
28
  lower_limit: Optional[Limit]
28
29
  upper_limit: Optional[Limit]
29
30
  validity: ValidType
31
+ value_type: DataType
30
32
 
31
33
  @staticmethod
32
- def from_et(et_element: ElementTree.Element, internal_type: DataType) -> "ScaleConstr":
34
+ def scale_constr_from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment], *,
35
+ value_type: DataType) -> "ScaleConstr":
33
36
  short_label = et_element.findtext("SHORT-LABEL")
34
- description = create_description_from_et(et_element.find("DESC"))
37
+ description = Description.from_et(et_element.find("DESC"), doc_frags)
35
38
 
36
- lower_limit = Limit.from_et(et_element.find("LOWER-LIMIT"), internal_type=internal_type)
37
- upper_limit = Limit.from_et(et_element.find("UPPER-LIMIT"), internal_type=internal_type)
39
+ lower_limit = Limit.limit_from_et(
40
+ et_element.find("LOWER-LIMIT"), doc_frags, value_type=value_type)
41
+ upper_limit = Limit.limit_from_et(
42
+ et_element.find("UPPER-LIMIT"), doc_frags, value_type=value_type)
38
43
 
39
44
  validity_str = odxrequire(et_element.get("VALIDITY"))
40
45
  try:
@@ -47,4 +52,5 @@ class ScaleConstr:
47
52
  description=description,
48
53
  lower_limit=lower_limit,
49
54
  upper_limit=upper_limit,
50
- validity=validity)
55
+ validity=validity,
56
+ value_type=value_type)
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()
odxtools/singleecujob.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 .diagcomm import DiagComm
@@ -10,11 +10,9 @@ from .negoutputparam import NegOutputParam
10
10
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
11
11
  from .outputparam import OutputParam
12
12
  from .progcode import ProgCode
13
+ from .snrefcontext import SnRefContext
13
14
  from .utils import dataclass_fields_asdict
14
15
 
15
- if TYPE_CHECKING:
16
- from .diaglayer import DiagLayer
17
-
18
16
 
19
17
  @dataclass
20
18
  class SingleEcuJob(DiagComm):
@@ -88,14 +86,18 @@ class SingleEcuJob(DiagComm):
88
86
  for neg_output_param in self.neg_output_params:
89
87
  neg_output_param._resolve_odxlinks(odxlinks)
90
88
 
91
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
92
- super()._resolve_snrefs(diag_layer)
89
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
90
+ context.single_ecu_job = self
91
+
92
+ super()._resolve_snrefs(context)
93
93
 
94
94
  for prog_code in self.prog_codes:
95
- prog_code._resolve_snrefs(diag_layer)
95
+ prog_code._resolve_snrefs(context)
96
96
  for input_param in self.input_params:
97
- input_param._resolve_snrefs(diag_layer)
97
+ input_param._resolve_snrefs(context)
98
98
  for output_param in self.output_params:
99
- output_param._resolve_snrefs(diag_layer)
99
+ output_param._resolve_snrefs(context)
100
100
  for neg_output_param in self.neg_output_params:
101
- neg_output_param._resolve_snrefs(diag_layer)
101
+ neg_output_param._resolve_snrefs(context)
102
+
103
+ context.single_ecu_job = None
@@ -0,0 +1,29 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import TYPE_CHECKING, List, Optional
4
+
5
+ if TYPE_CHECKING:
6
+ from .database import Database
7
+ from .diaglayers.diaglayer import DiagLayer
8
+ from .diagservice import DiagService
9
+ from .parameters.parameter import Parameter
10
+ from .request import Request
11
+ from .response import Response
12
+ from .singleecujob import SingleEcuJob
13
+ from .statechart import StateChart
14
+
15
+
16
+ @dataclass
17
+ class SnRefContext:
18
+ """Represents the context for which a short name reference ought
19
+ to be resolved
20
+ """
21
+
22
+ database: Optional["Database"] = None
23
+ diag_layer: Optional["DiagLayer"] = None
24
+ diag_service: Optional["DiagService"] = None
25
+ single_ecu_job: Optional["SingleEcuJob"] = None
26
+ request: Optional["Request"] = None
27
+ response: Optional["Response"] = None
28
+ parameters: Optional[List["Parameter"]] = None
29
+ state_chart: Optional["StateChart"] = None
odxtools/specialdata.py CHANGED
@@ -1,12 +1,10 @@
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
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
7
-
8
- if TYPE_CHECKING:
9
- from .diaglayer import DiagLayer
7
+ from .snrefcontext import SnRefContext
10
8
 
11
9
 
12
10
  @dataclass
@@ -21,7 +19,7 @@ class SpecialData:
21
19
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
22
20
  pass
23
21
 
24
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
22
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
25
23
  pass
26
24
 
27
25
  @staticmethod
@@ -1,22 +1,20 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
3
+ from typing import Any, Dict, List, Optional, Union
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
7
+ from .snrefcontext import SnRefContext
7
8
  from .specialdata import SpecialData
8
9
  from .specialdatagroupcaption import SpecialDataGroupCaption
9
10
 
10
- if TYPE_CHECKING:
11
- from .diaglayer import DiagLayer
12
-
13
11
 
14
12
  @dataclass
15
13
  class SpecialDataGroup:
16
14
  sdg_caption: Optional[SpecialDataGroupCaption]
17
15
  sdg_caption_ref: Optional[OdxLinkRef]
18
- semantic_info: Optional[str] # the "SI" attribute
19
16
  values: List[Union["SpecialDataGroup", SpecialData]]
17
+ semantic_info: Optional[str] # the "SI" attribute
20
18
 
21
19
  @staticmethod
22
20
  def from_et(et_element: ElementTree.Element,
@@ -53,7 +51,7 @@ class SpecialDataGroup:
53
51
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
54
52
  result = {}
55
53
 
56
- if self.sdg_caption is not None:
54
+ if self.sdg_caption_ref is None and self.sdg_caption is not None:
57
55
  result.update(self.sdg_caption._build_odxlinks())
58
56
 
59
57
  for val in self.values:
@@ -72,11 +70,11 @@ class SpecialDataGroup:
72
70
  for val in self.values:
73
71
  val._resolve_odxlinks(odxlinks)
74
72
 
75
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
73
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
76
74
  # resolve the SNREFs of the caption, but only if the caption
77
75
  # was specified by value, not by reference
78
76
  if self.sdg_caption is not None and self.sdg_caption_ref is None:
79
- self.sdg_caption._resolve_snrefs(diag_layer)
77
+ self.sdg_caption._resolve_snrefs(context)
80
78
 
81
79
  for val in self.values:
82
- val._resolve_snrefs(diag_layer)
80
+ val._resolve_snrefs(context)
@@ -1,16 +1,13 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # import warnings
3
2
  from dataclasses import dataclass
4
- from typing import TYPE_CHECKING, Any, Dict, List
3
+ from typing import Any, Dict, List
5
4
  from xml.etree import ElementTree
6
5
 
7
6
  from .element import IdentifiableElement
8
7
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
8
+ from .snrefcontext import SnRefContext
9
9
  from .utils import dataclass_fields_asdict
10
10
 
11
- if TYPE_CHECKING:
12
- from .diaglayer import DiagLayer
13
-
14
11
 
15
12
  @dataclass
16
13
  class SpecialDataGroupCaption(IdentifiableElement):
@@ -32,5 +29,5 @@ class SpecialDataGroupCaption(IdentifiableElement):
32
29
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
33
30
  pass
34
31
 
35
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
32
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
36
33
  pass