odxtools 10.1.1__py3-none-any.whl → 10.2.1__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 (112) hide show
  1. odxtools/addrdeffilter.py +33 -0
  2. odxtools/addrdefphyssegment.py +33 -0
  3. odxtools/checksum.py +67 -0
  4. odxtools/checksumresult.py +7 -0
  5. odxtools/database.py +24 -4
  6. odxtools/datablock.py +153 -0
  7. odxtools/datafile.py +23 -0
  8. odxtools/dataformat.py +39 -0
  9. odxtools/dataformatselection.py +9 -0
  10. odxtools/description.py +2 -5
  11. odxtools/diagdatadictionaryspec.py +1 -3
  12. odxtools/diaglayers/diaglayer.py +31 -11
  13. odxtools/diaglayers/ecuvariant.py +12 -19
  14. odxtools/diaglayers/hierarchyelement.py +5 -5
  15. odxtools/diaglayers/protocol.py +14 -0
  16. odxtools/direction.py +7 -0
  17. odxtools/ecumem.py +71 -0
  18. odxtools/ecumemconnector.py +136 -0
  19. odxtools/encryptcompressmethod.py +39 -0
  20. odxtools/encryptcompressmethodtype.py +13 -0
  21. odxtools/expectedident.py +40 -0
  22. odxtools/externflashdata.py +34 -0
  23. odxtools/filter.py +32 -0
  24. odxtools/flash.py +88 -0
  25. odxtools/flashclass.py +32 -0
  26. odxtools/flashdata.py +70 -0
  27. odxtools/fwchecksum.py +7 -0
  28. odxtools/fwsignature.py +7 -0
  29. odxtools/identdesc.py +54 -0
  30. odxtools/identvalue.py +32 -0
  31. odxtools/identvaluetype.py +14 -0
  32. odxtools/internflashdata.py +33 -0
  33. odxtools/loadfile.py +1 -1
  34. odxtools/mem.py +80 -0
  35. odxtools/modification.py +3 -2
  36. odxtools/negoffset.py +21 -0
  37. odxtools/odxlink.py +4 -2
  38. odxtools/ownident.py +38 -0
  39. odxtools/physicaltype.py +12 -10
  40. odxtools/physmem.py +52 -0
  41. odxtools/physsegment.py +42 -0
  42. odxtools/posoffset.py +21 -0
  43. odxtools/security.py +42 -0
  44. odxtools/securitymethod.py +7 -0
  45. odxtools/segment.py +63 -0
  46. odxtools/session.py +88 -0
  47. odxtools/sessiondesc.py +101 -0
  48. odxtools/sessionsubelemtype.py +14 -0
  49. odxtools/sizedeffilter.py +33 -0
  50. odxtools/sizedefphyssegment.py +33 -0
  51. odxtools/specialdata.py +2 -1
  52. odxtools/subcomponentparamconnector.py +1 -1
  53. odxtools/targetaddroffset.py +13 -0
  54. odxtools/templates/comparam-spec.odx-c.xml.jinja2 +1 -0
  55. odxtools/templates/comparam-subset.odx-cs.xml.jinja2 +1 -0
  56. odxtools/templates/diag_layer_container.odx-d.xml.jinja2 +2 -1
  57. odxtools/templates/flash.odx-f.xml.jinja2 +42 -0
  58. odxtools/templates/macros/printAdminData.xml.jinja2 +4 -4
  59. odxtools/templates/macros/printAudience.xml.jinja2 +3 -3
  60. odxtools/templates/macros/printChecksum.xml.jinja2 +36 -0
  61. odxtools/templates/macros/printComparam.xml.jinja2 +1 -1
  62. odxtools/templates/macros/printComparamRef.xml.jinja2 +1 -3
  63. odxtools/templates/macros/printCompuMethod.xml.jinja2 +1 -1
  64. odxtools/templates/macros/printDOP.xml.jinja2 +3 -3
  65. odxtools/templates/macros/printDatablock.xml.jinja2 +78 -0
  66. odxtools/templates/macros/printDiagComm.xml.jinja2 +2 -2
  67. odxtools/templates/macros/printDiagLayer.xml.jinja2 +2 -1
  68. odxtools/templates/macros/printDiagVariable.xml.jinja2 +4 -4
  69. odxtools/templates/macros/printDynDefinedSpec.xml.jinja2 +3 -3
  70. odxtools/templates/macros/printDynamicEndmarkerField.xml.jinja2 +2 -2
  71. odxtools/templates/macros/printDynamicLengthField.xml.jinja2 +2 -2
  72. odxtools/templates/macros/printEcuMem.xml.jinja2 +24 -0
  73. odxtools/templates/macros/printEcuMemConnector.xml.jinja2 +58 -0
  74. odxtools/templates/macros/printEndOfPdu.xml.jinja2 +1 -1
  75. odxtools/templates/macros/printEnvDataDesc.xml.jinja2 +1 -1
  76. odxtools/templates/macros/printExpectedIdent.xml.jinja2 +21 -0
  77. odxtools/templates/macros/printFlashdata.xml.jinja2 +43 -0
  78. odxtools/templates/macros/printIdentDesc.xml.jinja2 +17 -0
  79. odxtools/templates/macros/printMem.xml.jinja2 +35 -0
  80. odxtools/templates/macros/printMux.xml.jinja2 +3 -3
  81. odxtools/templates/macros/printOdxCategory.xml.jinja2 +4 -4
  82. odxtools/templates/macros/printOwnIdent.xml.jinja2 +17 -0
  83. odxtools/templates/macros/printParam.xml.jinja2 +4 -4
  84. odxtools/templates/macros/printParentRef.xml.jinja2 +1 -5
  85. odxtools/templates/macros/printPhysMem.xml.jinja2 +20 -0
  86. odxtools/templates/macros/printPhysSegment.xml.jinja2 +33 -0
  87. odxtools/templates/macros/printPreConditionStateRef.xml.jinja2 +1 -1
  88. odxtools/templates/macros/printProtStack.xml.jinja2 +1 -1
  89. odxtools/templates/macros/printProtocol.xml.jinja2 +1 -1
  90. odxtools/templates/macros/printSecurity.xml.jinja2 +37 -0
  91. odxtools/templates/macros/printSegment.xml.jinja2 +31 -0
  92. odxtools/templates/macros/printService.xml.jinja2 +3 -3
  93. odxtools/templates/macros/printSession.xml.jinja2 +45 -0
  94. odxtools/templates/macros/printSessionDesc.xml.jinja2 +40 -0
  95. odxtools/templates/macros/printSingleEcuJob.xml.jinja2 +3 -3
  96. odxtools/templates/macros/printSpecialData.xml.jinja2 +2 -2
  97. odxtools/templates/macros/printStateTransitionRef.xml.jinja2 +1 -1
  98. odxtools/templates/macros/printStaticField.xml.jinja2 +1 -1
  99. odxtools/templates/macros/printSubComponent.xml.jinja2 +3 -3
  100. odxtools/templates/macros/printTable.xml.jinja2 +6 -6
  101. odxtools/templates/macros/printUnitSpec.xml.jinja2 +2 -2
  102. odxtools/text.py +2 -6
  103. odxtools/utils.py +22 -1
  104. odxtools/validityfor.py +30 -0
  105. odxtools/version.py +2 -2
  106. odxtools/writepdxfile.py +70 -21
  107. {odxtools-10.1.1.dist-info → odxtools-10.2.1.dist-info}/METADATA +1 -1
  108. {odxtools-10.1.1.dist-info → odxtools-10.2.1.dist-info}/RECORD +112 -55
  109. {odxtools-10.1.1.dist-info → odxtools-10.2.1.dist-info}/WHEEL +1 -1
  110. {odxtools-10.1.1.dist-info → odxtools-10.2.1.dist-info}/entry_points.txt +0 -0
  111. {odxtools-10.1.1.dist-info → odxtools-10.2.1.dist-info}/licenses/LICENSE +0 -0
  112. {odxtools-10.1.1.dist-info → odxtools-10.2.1.dist-info}/top_level.txt +0 -0
@@ -7,6 +7,8 @@ from xml.etree import ElementTree
7
7
  from ..comparamspec import ComparamSpec
8
8
  from ..exceptions import odxassert
9
9
  from ..odxdoccontext import OdxDocContext
10
+ from ..odxlink import OdxLinkRef
11
+ from ..parentref import ParentRef
10
12
  from ..protstack import ProtStack
11
13
  from .hierarchyelement import HierarchyElement
12
14
  from .protocolraw import ProtocolRaw
@@ -24,14 +26,26 @@ class Protocol(HierarchyElement):
24
26
  def protocol_raw(self) -> ProtocolRaw:
25
27
  return cast(ProtocolRaw, self.diag_layer_raw)
26
28
 
29
+ @property
30
+ def comparam_spec_ref(self) -> OdxLinkRef:
31
+ return self.protocol_raw.comparam_spec_ref
32
+
27
33
  @property
28
34
  def comparam_spec(self) -> ComparamSpec:
29
35
  return self.protocol_raw.comparam_spec
30
36
 
37
+ @property
38
+ def prot_stack_snref(self) -> str | None:
39
+ return self.protocol_raw.prot_stack_snref
40
+
31
41
  @property
32
42
  def prot_stack(self) -> ProtStack | None:
33
43
  return self.protocol_raw.prot_stack
34
44
 
45
+ @property
46
+ def parent_refs(self) -> list[ParentRef]:
47
+ return self.protocol_raw.parent_refs
48
+
35
49
  @staticmethod
36
50
  def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "Protocol":
37
51
  protocol_raw = ProtocolRaw.from_et(et_element, context)
odxtools/direction.py ADDED
@@ -0,0 +1,7 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from enum import Enum
3
+
4
+
5
+ class Direction(Enum):
6
+ UPLOAD = "UPLOAD"
7
+ DOWNLOAD = "DOWNLOAD"
odxtools/ecumem.py ADDED
@@ -0,0 +1,71 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass, field
3
+ from typing import Any
4
+ from xml.etree import ElementTree
5
+
6
+ from .admindata import AdminData
7
+ from .element import IdentifiableElement
8
+ from .exceptions import odxrequire
9
+ from .mem import Mem
10
+ from .odxdoccontext import OdxDocContext
11
+ from .odxlink import OdxLinkDatabase, OdxLinkId
12
+ from .physmem import PhysMem
13
+ from .snrefcontext import SnRefContext
14
+ from .specialdatagroup import SpecialDataGroup
15
+ from .utils import dataclass_fields_asdict
16
+
17
+
18
+ @dataclass(kw_only=True)
19
+ class EcuMem(IdentifiableElement):
20
+ admin_data: AdminData | None = None
21
+ mem: Mem
22
+ phys_mem: PhysMem | None = None
23
+ sdgs: list[SpecialDataGroup] = field(default_factory=list)
24
+
25
+ @staticmethod
26
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "EcuMem":
27
+
28
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
29
+
30
+ admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), context)
31
+ mem = Mem.from_et(odxrequire(et_element.find("MEM")), context)
32
+ phys_mem = None
33
+ if (phys_mem_elem := et_element.find("PHYS-MEM")) is not None:
34
+ phys_mem = PhysMem.from_et(phys_mem_elem, context)
35
+ sdgs = [SpecialDataGroup.from_et(sdge, context) for sdge in et_element.iterfind("SDGS/SDG")]
36
+
37
+ return EcuMem(admin_data=admin_data, mem=mem, phys_mem=phys_mem, sdgs=sdgs, **kwargs)
38
+
39
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
40
+ odxlinks = {self.odx_id: self}
41
+
42
+ if self.admin_data is not None:
43
+ odxlinks.update(self.admin_data._build_odxlinks())
44
+
45
+ odxlinks.update(self.mem._build_odxlinks())
46
+ if self.phys_mem is not None:
47
+ odxlinks.update(self.phys_mem._build_odxlinks())
48
+ for sdg in self.sdgs:
49
+ odxlinks.update(sdg._build_odxlinks())
50
+
51
+ return odxlinks
52
+
53
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
54
+ if self.admin_data is not None:
55
+ self.admin_data._resolve_odxlinks(odxlinks)
56
+
57
+ self.mem._resolve_odxlinks(odxlinks)
58
+ if self.phys_mem is not None:
59
+ self.phys_mem._resolve_odxlinks(odxlinks)
60
+ for sdg in self.sdgs:
61
+ sdg._resolve_odxlinks(odxlinks)
62
+
63
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
64
+ if self.admin_data is not None:
65
+ self.admin_data._resolve_snrefs(context)
66
+
67
+ self.mem._resolve_snrefs(context)
68
+ if self.phys_mem is not None:
69
+ self.phys_mem._resolve_snrefs(context)
70
+ for sdg in self.sdgs:
71
+ sdg._resolve_snrefs(context)
@@ -0,0 +1,136 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass, field
3
+ from typing import Any
4
+ from xml.etree import ElementTree
5
+
6
+ from .admindata import AdminData
7
+ from .diaglayers.basevariant import BaseVariant
8
+ from .diaglayers.ecuvariant import EcuVariant
9
+ from .ecumem import EcuMem
10
+ from .element import IdentifiableElement
11
+ from .exceptions import odxraise, odxrequire
12
+ from .flashclass import FlashClass
13
+ from .identdesc import IdentDesc
14
+ from .nameditemlist import NamedItemList
15
+ from .odxdoccontext import OdxDocContext
16
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
17
+ from .sessiondesc import SessionDesc
18
+ from .snrefcontext import SnRefContext
19
+ from .specialdatagroup import SpecialDataGroup
20
+ from .utils import dataclass_fields_asdict
21
+
22
+
23
+ @dataclass(kw_only=True)
24
+ class EcuMemConnector(IdentifiableElement):
25
+ admin_data: AdminData | None = None
26
+ flash_classes: NamedItemList[FlashClass]
27
+ session_descs: NamedItemList[SessionDesc] = field(default_factory=NamedItemList)
28
+ ident_descs: list[IdentDesc] = field(default_factory=list)
29
+ ecu_mem_ref: OdxLinkRef
30
+ layer_refs: list[OdxLinkRef]
31
+ all_variant_refs: list[OdxLinkRef]
32
+ sdgs: list[SpecialDataGroup] = field(default_factory=list)
33
+
34
+ @property
35
+ def ecu_mem(self) -> EcuMem:
36
+ return self._ecu_mem
37
+
38
+ @property
39
+ def layers(self) -> NamedItemList[EcuVariant | BaseVariant]:
40
+ return self._layers
41
+
42
+ @property
43
+ def all_variants(self) -> NamedItemList[BaseVariant]:
44
+ return self._all_variants
45
+
46
+ @staticmethod
47
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "EcuMemConnector":
48
+
49
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
50
+
51
+ admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), context)
52
+ flash_classes = NamedItemList([
53
+ FlashClass.from_et(el, context)
54
+ for el in et_element.iterfind("FLASH-CLASSS/FLASH-CLASS")
55
+ ])
56
+ session_descs = NamedItemList([
57
+ SessionDesc.from_et(el, context)
58
+ for el in et_element.iterfind("SESSION-DESCS/SESSION-DESC")
59
+ ])
60
+ ident_descs = [
61
+ IdentDesc.from_et(el, context) for el in et_element.iterfind("IDENT-DESCS/IDENT-DESC")
62
+ ]
63
+ ecu_mem_ref = OdxLinkRef.from_et(odxrequire(et_element.find("ECU-MEM-REF")), context)
64
+ layer_refs = [
65
+ OdxLinkRef.from_et(el, context) for el in et_element.iterfind("LAYER-REFS/LAYER-REF")
66
+ ]
67
+ all_variant_refs = [
68
+ OdxLinkRef.from_et(el, context)
69
+ for el in et_element.iterfind("ALL-VARIANT-REFS/ALL-VARIANT-REF")
70
+ ]
71
+ sdgs = [SpecialDataGroup.from_et(sdge, context) for sdge in et_element.iterfind("SDGS/SDG")]
72
+
73
+ return EcuMemConnector(
74
+ admin_data=admin_data,
75
+ flash_classes=flash_classes,
76
+ session_descs=session_descs,
77
+ ident_descs=ident_descs,
78
+ ecu_mem_ref=ecu_mem_ref,
79
+ layer_refs=layer_refs,
80
+ all_variant_refs=all_variant_refs,
81
+ sdgs=sdgs,
82
+ **kwargs)
83
+
84
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
85
+ odxlinks = {self.odx_id: self}
86
+
87
+ if self.admin_data is not None:
88
+ odxlinks.update(self.admin_data._build_odxlinks())
89
+ for flash_class in self.flash_classes:
90
+ odxlinks.update(flash_class._build_odxlinks())
91
+ for session_desc in self.session_descs:
92
+ odxlinks.update(session_desc._build_odxlinks())
93
+ for ident_desc in self.ident_descs:
94
+ odxlinks.update(ident_desc._build_odxlinks())
95
+ for sdg in self.sdgs:
96
+ odxlinks.update(sdg._build_odxlinks())
97
+
98
+ return odxlinks
99
+
100
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
101
+ self._ecu_mem = odxlinks.resolve(self.ecu_mem_ref, EcuMem)
102
+
103
+ tmp = []
104
+ for ref in self.layer_refs:
105
+ x = odxlinks.resolve(ref)
106
+ if not isinstance(x, (BaseVariant, EcuVariant)):
107
+ odxraise("Invalid type of referenced object")
108
+ tmp.append(x)
109
+ self._layers = NamedItemList(tmp)
110
+
111
+ self._all_variants = NamedItemList(
112
+ [odxlinks.resolve(ref, BaseVariant) for ref in self.all_variant_refs])
113
+ self._ecu_mem = odxlinks.resolve(self.ecu_mem_ref, EcuMem)
114
+
115
+ if self.admin_data is not None:
116
+ self.admin_data._resolve_odxlinks(odxlinks)
117
+ for flash_class in self.flash_classes:
118
+ flash_class._resolve_odxlinks(odxlinks)
119
+ for session_desc in self.session_descs:
120
+ session_desc._resolve_odxlinks(odxlinks)
121
+ for ident_desc in self.ident_descs:
122
+ ident_desc._resolve_odxlinks(odxlinks)
123
+ for sdg in self.sdgs:
124
+ sdg._resolve_odxlinks(odxlinks)
125
+
126
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
127
+ if self.admin_data is not None:
128
+ self.admin_data._resolve_snrefs(context)
129
+ for flash_class in self.flash_classes:
130
+ flash_class._resolve_snrefs(context)
131
+ for session_desc in self.session_descs:
132
+ session_desc._resolve_snrefs(context)
133
+ for ident_desc in self.ident_descs:
134
+ ident_desc._resolve_snrefs(context)
135
+ for sdg in self.sdgs:
136
+ sdg._resolve_snrefs(context)
@@ -0,0 +1,39 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, cast
3
+ from xml.etree import ElementTree
4
+
5
+ from .encryptcompressmethodtype import EncryptCompressMethodType
6
+ from .exceptions import odxraise, odxrequire
7
+ from .odxdoccontext import OdxDocContext
8
+ from .odxlink import OdxLinkDatabase, OdxLinkId
9
+ from .snrefcontext import SnRefContext
10
+
11
+
12
+ @dataclass(kw_only=True)
13
+ class EncryptCompressMethod:
14
+ value: str
15
+ value_type: EncryptCompressMethodType
16
+
17
+ @staticmethod
18
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "EncryptCompressMethod":
19
+ value = et_element.text or ""
20
+
21
+ value_type_str = odxrequire(et_element.attrib.get("TYPE"))
22
+ try:
23
+ value_type = EncryptCompressMethodType(value_type_str)
24
+ except ValueError:
25
+ value_type = cast(EncryptCompressMethodType, None)
26
+ odxraise(f"Encountered unknown addressing type '{value_type_str}'")
27
+
28
+ return EncryptCompressMethod(value=value, value_type=value_type)
29
+
30
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
31
+ odxlinks: dict[OdxLinkId, Any] = {}
32
+
33
+ return odxlinks
34
+
35
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
36
+ pass
37
+
38
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
39
+ pass
@@ -0,0 +1,13 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from enum import Enum
3
+
4
+ from .odxtypes import DataType
5
+
6
+
7
+ class EncryptCompressMethodType(Enum):
8
+ A_UINT32 = "A_UINT32"
9
+ A_BYTEFIELD = "A_BYTEFIELD"
10
+
11
+ @property
12
+ def data_type(self) -> DataType:
13
+ return DataType(self.value)
@@ -0,0 +1,40 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import Any
4
+ from xml.etree import ElementTree
5
+
6
+ from .element import IdentifiableElement
7
+ from .identvalue import IdentValue
8
+ from .odxdoccontext import OdxDocContext
9
+ from .odxlink import OdxLinkDatabase, OdxLinkId
10
+ from .snrefcontext import SnRefContext
11
+ from .utils import dataclass_fields_asdict
12
+
13
+
14
+ @dataclass(kw_only=True)
15
+ class ExpectedIdent(IdentifiableElement):
16
+ """
17
+ Corresponds to EXPECTED-IDENT.
18
+ """
19
+
20
+ ident_values: list[IdentValue]
21
+
22
+ @staticmethod
23
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "ExpectedIdent":
24
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
25
+
26
+ ident_values = [
27
+ IdentValue.from_et(ive, context)
28
+ for ive in et_element.iterfind("IDENT-VALUES/IDENT-VALUE")
29
+ ]
30
+
31
+ return ExpectedIdent(ident_values=ident_values, **kwargs)
32
+
33
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
34
+ return {self.odx_id: self}
35
+
36
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
37
+ pass
38
+
39
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
40
+ pass
@@ -0,0 +1,34 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import Any
4
+ from xml.etree import ElementTree
5
+
6
+ from .datafile import Datafile
7
+ from .exceptions import odxrequire
8
+ from .flashdata import Flashdata
9
+ from .odxdoccontext import OdxDocContext
10
+ from .odxlink import OdxLinkDatabase, OdxLinkId
11
+ from .snrefcontext import SnRefContext
12
+ from .utils import dataclass_fields_asdict
13
+
14
+
15
+ @dataclass(kw_only=True)
16
+ class ExternFlashdata(Flashdata):
17
+ datafile: Datafile
18
+
19
+ @staticmethod
20
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "ExternFlashdata":
21
+ kwargs = dataclass_fields_asdict(Flashdata.from_et(et_element, context))
22
+
23
+ datafile = Datafile.from_et(odxrequire(et_element.find("DATAFILE")), context)
24
+
25
+ return ExternFlashdata(datafile=datafile, **kwargs)
26
+
27
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
28
+ return super()._build_odxlinks()
29
+
30
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
31
+ super()._resolve_odxlinks(odxlinks)
32
+
33
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
34
+ super()._resolve_snrefs(context)
odxtools/filter.py ADDED
@@ -0,0 +1,32 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import Any
4
+ from xml.etree import ElementTree
5
+
6
+ from .exceptions import odxrequire
7
+ from .odxdoccontext import OdxDocContext
8
+ from .odxlink import OdxLinkDatabase, OdxLinkId
9
+ from .snrefcontext import SnRefContext
10
+ from .utils import read_hex_binary
11
+
12
+
13
+ @dataclass(kw_only=True)
14
+ class Filter:
15
+ filter_start: int
16
+
17
+ @staticmethod
18
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "Filter":
19
+ filter_start = odxrequire(read_hex_binary(et_element.find("FILTER-START")))
20
+
21
+ return Filter(filter_start=filter_start)
22
+
23
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
24
+ odxlinks: dict[OdxLinkId, Any] = {}
25
+
26
+ return odxlinks
27
+
28
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
29
+ pass
30
+
31
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
32
+ pass
odxtools/flash.py ADDED
@@ -0,0 +1,88 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass, field
3
+ from typing import TYPE_CHECKING, Any
4
+ from xml.etree import ElementTree
5
+
6
+ from .additionalaudience import AdditionalAudience
7
+ from .ecumem import EcuMem
8
+ from .ecumemconnector import EcuMemConnector
9
+ from .nameditemlist import NamedItemList
10
+ from .odxcategory import OdxCategory
11
+ from .odxdoccontext import OdxDocContext
12
+ from .odxlink import OdxLinkDatabase, OdxLinkId
13
+ from .snrefcontext import SnRefContext
14
+ from .utils import dataclass_fields_asdict
15
+
16
+ if TYPE_CHECKING:
17
+ from .database import Database
18
+
19
+
20
+ @dataclass(kw_only=True)
21
+ class Flash(OdxCategory):
22
+ ecu_mems: NamedItemList[EcuMem] = field(default_factory=NamedItemList)
23
+ ecu_mem_connectors: NamedItemList[EcuMemConnector] = field(default_factory=NamedItemList)
24
+ additional_audiences: NamedItemList[AdditionalAudience] = field(default_factory=NamedItemList)
25
+
26
+ @staticmethod
27
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "Flash":
28
+
29
+ base_obj = OdxCategory.from_et(et_element, context)
30
+ kwargs = dataclass_fields_asdict(base_obj)
31
+
32
+ ecu_mems = NamedItemList(
33
+ [EcuMem.from_et(el, context) for el in et_element.iterfind("ECU-MEMS/ECU-MEM")])
34
+ ecu_mem_connectors = NamedItemList([
35
+ EcuMemConnector.from_et(el, context)
36
+ for el in et_element.iterfind("ECU-MEM-CONNECTORS/ECU-MEM-CONNECTOR")
37
+ ])
38
+ additional_audiences = NamedItemList([
39
+ AdditionalAudience.from_et(el, context)
40
+ for el in et_element.iterfind("ADDITIONAL-AUDIENCES/ADDITIONAL-AUDIENCE")
41
+ ])
42
+
43
+ return Flash(
44
+ ecu_mems=ecu_mems,
45
+ ecu_mem_connectors=ecu_mem_connectors,
46
+ additional_audiences=additional_audiences,
47
+ **kwargs)
48
+
49
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
50
+ odxlinks = super()._build_odxlinks()
51
+
52
+ for ecu_mem in self.ecu_mems:
53
+ odxlinks.update(ecu_mem._build_odxlinks())
54
+
55
+ for ecu_mem_connector in self.ecu_mem_connectors:
56
+ odxlinks.update(ecu_mem_connector._build_odxlinks())
57
+
58
+ for additional_audiences in self.additional_audiences:
59
+ odxlinks.update(additional_audiences._build_odxlinks())
60
+
61
+ return odxlinks
62
+
63
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
64
+ super()._resolve_odxlinks(odxlinks)
65
+
66
+ for ecu_mem in self.ecu_mems:
67
+ ecu_mem._resolve_odxlinks(odxlinks)
68
+
69
+ for ecu_mem_connector in self.ecu_mem_connectors:
70
+ ecu_mem_connector._resolve_odxlinks(odxlinks)
71
+
72
+ for additional_audiences in self.additional_audiences:
73
+ additional_audiences._resolve_odxlinks(odxlinks)
74
+
75
+ def _finalize_init(self, database: "Database", odxlinks: OdxLinkDatabase) -> None:
76
+ super()._finalize_init(database, odxlinks)
77
+
78
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
79
+ super()._resolve_snrefs(context)
80
+
81
+ for ecu_mem in self.ecu_mems:
82
+ ecu_mem._resolve_snrefs(context)
83
+
84
+ for ecu_mem_connector in self.ecu_mem_connectors:
85
+ ecu_mem_connector._resolve_snrefs(context)
86
+
87
+ for additional_audiences in self.additional_audiences:
88
+ additional_audiences._resolve_snrefs(context)
odxtools/flashclass.py ADDED
@@ -0,0 +1,32 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import Any
4
+ from xml.etree import ElementTree
5
+
6
+ from .element import IdentifiableElement
7
+ from .odxdoccontext import OdxDocContext
8
+ from .odxlink import OdxLinkDatabase, OdxLinkId
9
+ from .snrefcontext import SnRefContext
10
+ from .utils import dataclass_fields_asdict
11
+
12
+
13
+ @dataclass(kw_only=True)
14
+ class FlashClass(IdentifiableElement):
15
+ """
16
+ Corresponds to FLASH-CLASS.
17
+ """
18
+
19
+ @staticmethod
20
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "FlashClass":
21
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
22
+
23
+ return FlashClass(**kwargs)
24
+
25
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
26
+ return {self.odx_id: self}
27
+
28
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
29
+ pass
30
+
31
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
32
+ pass
odxtools/flashdata.py ADDED
@@ -0,0 +1,70 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import Any
4
+ from xml.etree import ElementTree
5
+
6
+ from .dataformat import Dataformat
7
+ from .element import IdentifiableElement
8
+ from .encryptcompressmethod import EncryptCompressMethod
9
+ from .exceptions import odxrequire
10
+ from .odxdoccontext import OdxDocContext
11
+ from .odxlink import OdxLinkDatabase, OdxLinkId
12
+ from .snrefcontext import SnRefContext
13
+ from .utils import dataclass_fields_asdict
14
+
15
+
16
+ @dataclass(kw_only=True)
17
+ class Flashdata(IdentifiableElement):
18
+ size_length: int | None = None
19
+ address_length: int | None = None
20
+ dataformat: Dataformat
21
+ encrypt_compress_method: EncryptCompressMethod | None = None
22
+
23
+ @staticmethod
24
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "Flashdata":
25
+
26
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
27
+
28
+ size_length = None
29
+ if (size_length_str := et_element.findtext("SIZE-LENGTH")) is not None:
30
+ size_length = int(size_length_str)
31
+
32
+ address_length = None
33
+ if (address_length_str := et_element.findtext("ADDRESS-LENGTH")) is not None:
34
+ address_length = int(address_length_str)
35
+
36
+ dataformat = Dataformat.from_et(odxrequire(et_element.find("DATAFORMAT")), context)
37
+
38
+ encrypt_compress_method = None
39
+ if (encrypt_compress_method_elem := et_element.find("ENCRYPT-COMPRESS-METHOD")) is not None:
40
+ encrypt_compress_method = EncryptCompressMethod.from_et(encrypt_compress_method_elem,
41
+ context)
42
+
43
+ return Flashdata(
44
+ size_length=size_length,
45
+ address_length=address_length,
46
+ dataformat=dataformat,
47
+ encrypt_compress_method=encrypt_compress_method,
48
+ **kwargs)
49
+
50
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
51
+ odxlinks = {self.odx_id: self}
52
+
53
+ if self.dataformat is not None:
54
+ odxlinks.update(self.dataformat._build_odxlinks())
55
+ if self.encrypt_compress_method is not None:
56
+ odxlinks.update(self.encrypt_compress_method._build_odxlinks())
57
+
58
+ return odxlinks
59
+
60
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
61
+ if self.dataformat is not None:
62
+ self.dataformat._resolve_odxlinks(odxlinks)
63
+ if self.encrypt_compress_method is not None:
64
+ self.encrypt_compress_method._resolve_odxlinks(odxlinks)
65
+
66
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
67
+ if self.dataformat is not None:
68
+ self.dataformat._resolve_snrefs(context)
69
+ if self.encrypt_compress_method is not None:
70
+ self.encrypt_compress_method._resolve_snrefs(context)
odxtools/fwchecksum.py ADDED
@@ -0,0 +1,7 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from .validityfor import ValidityFor
3
+
4
+ # Note that the ODX specification specifies a separate tag for this,
5
+ # but this tag is identical to VALIDITY-FOR, so let's use a type alias
6
+ # to reduce the amount of copy-and-pasted code
7
+ FwChecksum = ValidityFor
@@ -0,0 +1,7 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from .validityfor import ValidityFor
3
+
4
+ # Note that the ODX specification specifies a separate tag for this,
5
+ # but this tag is identical to VALIDITY-FOR, so let's use a type alias
6
+ # to reduce the amount of copy-and-pasted code
7
+ FwSignature = ValidityFor
odxtools/identdesc.py ADDED
@@ -0,0 +1,54 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import Any
4
+ from xml.etree import ElementTree
5
+
6
+ from .exceptions import odxrequire
7
+ from .odxdoccontext import OdxDocContext
8
+ from .odxlink import OdxLinkDatabase, OdxLinkId
9
+ from .snrefcontext import SnRefContext
10
+
11
+
12
+ @dataclass(kw_only=True)
13
+ class IdentDesc:
14
+ diag_comm_snref: str
15
+ ident_if_snref: str
16
+
17
+ # exactly one of the two attributes below must be defined
18
+ out_param_if_snref: str | None = None
19
+ out_param_if_snpathref: str | None = None
20
+
21
+ @staticmethod
22
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "IdentDesc":
23
+ diag_comm_snref = odxrequire(
24
+ odxrequire(et_element.find("DIAG-COMM-SNREF")).attrib.get("SHORT-NAME"))
25
+ ident_if_snref = odxrequire(
26
+ odxrequire(et_element.find("IDENT-IF-SNREF")).attrib.get("SHORT-NAME"))
27
+ out_param_if_snref = None
28
+ if (out_param_if_snref_elem := et_element.find("OUT-PARAM-IF-SNREF")) is not None:
29
+ out_param_if_snref = odxrequire(out_param_if_snref_elem.attrib.get("SHORT-NAME"))
30
+
31
+ out_param_if_snpathref = None
32
+ if (out_param_if_snpathref_elem := et_element.find("OUT-PARAM-IF-SNPATHREF")) is not None:
33
+ out_param_if_snpathref = odxrequire(
34
+ out_param_if_snpathref_elem.attrib.get("SHORT-NAME-PATH"))
35
+
36
+ return IdentDesc(
37
+ diag_comm_snref=diag_comm_snref,
38
+ ident_if_snref=ident_if_snref,
39
+ out_param_if_snref=out_param_if_snref,
40
+ out_param_if_snpathref=out_param_if_snpathref,
41
+ )
42
+
43
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
44
+ odxlinks: dict[OdxLinkId, Any] = {}
45
+
46
+ return odxlinks
47
+
48
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
49
+ pass
50
+
51
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
52
+ # TODO: resolve the short name references. for IdentDesc this
53
+ # is (probably) not possible ahead of time...
54
+ pass