odxtools 10.1.1__py3-none-any.whl → 10.2.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 (106) 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/direction.py +7 -0
  13. odxtools/ecumem.py +71 -0
  14. odxtools/ecumemconnector.py +136 -0
  15. odxtools/encryptcompressmethod.py +39 -0
  16. odxtools/encryptcompressmethodtype.py +13 -0
  17. odxtools/expectedident.py +40 -0
  18. odxtools/externflashdata.py +34 -0
  19. odxtools/filter.py +32 -0
  20. odxtools/flash.py +88 -0
  21. odxtools/flashclass.py +32 -0
  22. odxtools/flashdata.py +70 -0
  23. odxtools/fwchecksum.py +7 -0
  24. odxtools/fwsignature.py +7 -0
  25. odxtools/identdesc.py +54 -0
  26. odxtools/identvalue.py +32 -0
  27. odxtools/identvaluetype.py +14 -0
  28. odxtools/internflashdata.py +33 -0
  29. odxtools/loadfile.py +1 -1
  30. odxtools/mem.py +80 -0
  31. odxtools/modification.py +3 -2
  32. odxtools/negoffset.py +21 -0
  33. odxtools/ownident.py +38 -0
  34. odxtools/physicaltype.py +12 -10
  35. odxtools/physmem.py +52 -0
  36. odxtools/physsegment.py +42 -0
  37. odxtools/posoffset.py +21 -0
  38. odxtools/security.py +42 -0
  39. odxtools/securitymethod.py +7 -0
  40. odxtools/segment.py +63 -0
  41. odxtools/session.py +88 -0
  42. odxtools/sessiondesc.py +101 -0
  43. odxtools/sessionsubelemtype.py +14 -0
  44. odxtools/sizedeffilter.py +33 -0
  45. odxtools/sizedefphyssegment.py +33 -0
  46. odxtools/specialdata.py +2 -1
  47. odxtools/targetaddroffset.py +13 -0
  48. odxtools/templates/comparam-spec.odx-c.xml.jinja2 +1 -0
  49. odxtools/templates/comparam-subset.odx-cs.xml.jinja2 +1 -0
  50. odxtools/templates/diag_layer_container.odx-d.xml.jinja2 +2 -1
  51. odxtools/templates/flash.odx-f.xml.jinja2 +42 -0
  52. odxtools/templates/macros/printAdminData.xml.jinja2 +4 -4
  53. odxtools/templates/macros/printAudience.xml.jinja2 +3 -3
  54. odxtools/templates/macros/printChecksum.xml.jinja2 +36 -0
  55. odxtools/templates/macros/printComparam.xml.jinja2 +1 -1
  56. odxtools/templates/macros/printComparamRef.xml.jinja2 +1 -3
  57. odxtools/templates/macros/printCompuMethod.xml.jinja2 +1 -1
  58. odxtools/templates/macros/printDOP.xml.jinja2 +3 -3
  59. odxtools/templates/macros/printDatablock.xml.jinja2 +78 -0
  60. odxtools/templates/macros/printDiagComm.xml.jinja2 +2 -2
  61. odxtools/templates/macros/printDiagLayer.xml.jinja2 +2 -1
  62. odxtools/templates/macros/printDiagVariable.xml.jinja2 +4 -4
  63. odxtools/templates/macros/printDynDefinedSpec.xml.jinja2 +3 -3
  64. odxtools/templates/macros/printDynamicEndmarkerField.xml.jinja2 +2 -2
  65. odxtools/templates/macros/printDynamicLengthField.xml.jinja2 +2 -2
  66. odxtools/templates/macros/printEcuMem.xml.jinja2 +24 -0
  67. odxtools/templates/macros/printEcuMemConnector.xml.jinja2 +58 -0
  68. odxtools/templates/macros/printEndOfPdu.xml.jinja2 +1 -1
  69. odxtools/templates/macros/printEnvDataDesc.xml.jinja2 +1 -1
  70. odxtools/templates/macros/printExpectedIdent.xml.jinja2 +21 -0
  71. odxtools/templates/macros/printFlashdata.xml.jinja2 +43 -0
  72. odxtools/templates/macros/printIdentDesc.xml.jinja2 +17 -0
  73. odxtools/templates/macros/printMem.xml.jinja2 +35 -0
  74. odxtools/templates/macros/printMux.xml.jinja2 +3 -3
  75. odxtools/templates/macros/printOdxCategory.xml.jinja2 +4 -4
  76. odxtools/templates/macros/printOwnIdent.xml.jinja2 +17 -0
  77. odxtools/templates/macros/printParam.xml.jinja2 +4 -4
  78. odxtools/templates/macros/printParentRef.xml.jinja2 +1 -5
  79. odxtools/templates/macros/printPhysMem.xml.jinja2 +20 -0
  80. odxtools/templates/macros/printPhysSegment.xml.jinja2 +33 -0
  81. odxtools/templates/macros/printPreConditionStateRef.xml.jinja2 +1 -1
  82. odxtools/templates/macros/printProtStack.xml.jinja2 +1 -1
  83. odxtools/templates/macros/printProtocol.xml.jinja2 +1 -1
  84. odxtools/templates/macros/printSecurity.xml.jinja2 +37 -0
  85. odxtools/templates/macros/printSegment.xml.jinja2 +31 -0
  86. odxtools/templates/macros/printService.xml.jinja2 +3 -3
  87. odxtools/templates/macros/printSession.xml.jinja2 +45 -0
  88. odxtools/templates/macros/printSessionDesc.xml.jinja2 +40 -0
  89. odxtools/templates/macros/printSingleEcuJob.xml.jinja2 +3 -3
  90. odxtools/templates/macros/printSpecialData.xml.jinja2 +2 -2
  91. odxtools/templates/macros/printStateTransitionRef.xml.jinja2 +1 -1
  92. odxtools/templates/macros/printStaticField.xml.jinja2 +1 -1
  93. odxtools/templates/macros/printSubComponent.xml.jinja2 +3 -3
  94. odxtools/templates/macros/printTable.xml.jinja2 +6 -6
  95. odxtools/templates/macros/printUnitSpec.xml.jinja2 +2 -2
  96. odxtools/text.py +2 -6
  97. odxtools/utils.py +22 -1
  98. odxtools/validityfor.py +30 -0
  99. odxtools/version.py +2 -2
  100. odxtools/writepdxfile.py +70 -21
  101. {odxtools-10.1.1.dist-info → odxtools-10.2.0.dist-info}/METADATA +1 -1
  102. {odxtools-10.1.1.dist-info → odxtools-10.2.0.dist-info}/RECORD +106 -49
  103. {odxtools-10.1.1.dist-info → odxtools-10.2.0.dist-info}/WHEEL +1 -1
  104. {odxtools-10.1.1.dist-info → odxtools-10.2.0.dist-info}/entry_points.txt +0 -0
  105. {odxtools-10.1.1.dist-info → odxtools-10.2.0.dist-info}/licenses/LICENSE +0 -0
  106. {odxtools-10.1.1.dist-info → odxtools-10.2.0.dist-info}/top_level.txt +0 -0
@@ -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
odxtools/identvalue.py ADDED
@@ -0,0 +1,32 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from xml.etree import ElementTree
4
+
5
+ from .exceptions import odxraise
6
+ from .identvaluetype import IdentValueType
7
+ from .odxdoccontext import OdxDocContext
8
+
9
+
10
+ @dataclass(kw_only=True)
11
+ class IdentValue:
12
+ """
13
+ Corresponds to IDENT-VALUE.
14
+ """
15
+
16
+ value: str
17
+
18
+ # note that the spec says this attribute is named "TYPE", but in
19
+ # python, "type" is a build-in function...
20
+ value_type: IdentValueType
21
+
22
+ @staticmethod
23
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "IdentValue":
24
+ value = et_element.text or ""
25
+
26
+ try:
27
+ value_type = IdentValueType(et_element.attrib["TYPE"])
28
+ except Exception as e:
29
+ odxraise(f"Cannot parse IDENT-VALUE-TYPE: {e}")
30
+ value_type = None
31
+
32
+ return IdentValue(value=value, value_type=value_type)
@@ -0,0 +1,14 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from enum import Enum
3
+
4
+ from .odxtypes import DataType
5
+
6
+
7
+ class IdentValueType(Enum):
8
+ A_UINT32 = "A_UINT32"
9
+ A_BYTEFIELD = "A_BYTEFIELD"
10
+ A_ASCIISTRING = "A_ASCIISTRING"
11
+
12
+ @property
13
+ def data_type(self) -> DataType:
14
+ return DataType(self.value)
@@ -0,0 +1,33 @@
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 .flashdata import Flashdata
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 InternFlashdata(Flashdata):
16
+ data: str
17
+
18
+ @staticmethod
19
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "InternFlashdata":
20
+ kwargs = dataclass_fields_asdict(Flashdata.from_et(et_element, context))
21
+
22
+ data = odxrequire(et_element.findtext("DATA"))
23
+
24
+ return InternFlashdata(data=data, **kwargs)
25
+
26
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
27
+ return super()._build_odxlinks()
28
+
29
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
30
+ super()._resolve_odxlinks(odxlinks)
31
+
32
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
33
+ super()._resolve_snrefs(context)
odxtools/loadfile.py CHANGED
@@ -23,7 +23,7 @@ def load_odx_d_file(odx_d_file_name: str | Path) -> Database:
23
23
  def load_file(file_name: str | Path) -> Database:
24
24
  if str(file_name).lower().endswith(".pdx"):
25
25
  return load_pdx_file(str(file_name))
26
- elif str(file_name).lower().endswith(".odx-d"):
26
+ elif Path(file_name).suffix.lower().startswith(".odx"):
27
27
  return load_odx_d_file(str(file_name))
28
28
  else:
29
29
  raise RuntimeError(f"Could not guess the file format of file '{file_name}'!")