odxtools 5.3.0__py3-none-any.whl → 5.3.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.
- odxtools/determinenumberofitems.py +18 -0
- odxtools/diagdatadictionaryspec.py +14 -4
- odxtools/diaglayer.py +54 -59
- odxtools/dynamiclengthfield.py +59 -0
- odxtools/element.py +2 -4
- odxtools/endofpdufield.py +6 -77
- odxtools/field.py +94 -0
- odxtools/multiplexer.py +6 -18
- odxtools/multiplexerswitchkey.py +8 -43
- odxtools/odxtypes.py +1 -1
- odxtools/parameters/lengthkeyparameter.py +1 -1
- odxtools/parameters/parameterwithdop.py +6 -1
- odxtools/positioneddataobjectproperty.py +74 -0
- odxtools/tablerow.py +1 -2
- odxtools/templates/macros/printAudience.xml.jinja2 +3 -9
- odxtools/templates/macros/printCompanyData.xml.jinja2 +4 -27
- odxtools/templates/macros/printComparam.xml.jinja2 +4 -18
- odxtools/templates/macros/printDOP.xml.jinja2 +3 -9
- odxtools/templates/macros/printDynamicLengthField.xml.jinja2 +22 -0
- odxtools/templates/macros/printElementID.xml.jinja2 +6 -6
- odxtools/templates/macros/printEndOfPdu.xml.jinja2 +3 -2
- odxtools/templates/macros/printEnvData.xml.jinja2 +2 -2
- odxtools/templates/macros/printEnvDataDesc.xml.jinja2 +3 -2
- odxtools/templates/macros/printFunctionalClass.xml.jinja2 +3 -9
- odxtools/templates/macros/printMux.xml.jinja2 +5 -6
- odxtools/templates/macros/printParam.xml.jinja2 +2 -7
- odxtools/templates/macros/printRequest.xml.jinja2 +2 -9
- odxtools/templates/macros/printResponse.xml.jinja2 +2 -9
- odxtools/templates/macros/printService.xml.jinja2 +2 -9
- odxtools/templates/macros/printSpecialData.xml.jinja2 +1 -1
- odxtools/templates/macros/printState.xml.jinja2 +3 -9
- odxtools/templates/macros/printStateChart.xml.jinja2 +2 -9
- odxtools/templates/macros/printStateTransition.xml.jinja2 +3 -9
- odxtools/templates/macros/printStructure.xml.jinja2 +2 -4
- odxtools/templates/macros/printTable.xml.jinja2 +2 -7
- odxtools/templates/macros/printUnitSpec.xml.jinja2 +3 -3
- odxtools/templates/macros/printVariant.xml.jinja2 +10 -9
- odxtools/version.py +4 -2
- {odxtools-5.3.0.dist-info → odxtools-5.3.1.dist-info}/METADATA +1 -1
- {odxtools-5.3.0.dist-info → odxtools-5.3.1.dist-info}/RECORD +44 -39
- {odxtools-5.3.0.dist-info → odxtools-5.3.1.dist-info}/LICENSE +0 -0
- {odxtools-5.3.0.dist-info → odxtools-5.3.1.dist-info}/WHEEL +0 -0
- {odxtools-5.3.0.dist-info → odxtools-5.3.1.dist-info}/entry_points.txt +0 -0
- {odxtools-5.3.0.dist-info → odxtools-5.3.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import List
|
3
|
+
from xml.etree import ElementTree
|
4
|
+
|
5
|
+
from .odxlink import OdxDocFragment
|
6
|
+
from .positioneddataobjectproperty import PositionedDataObjectProperty
|
7
|
+
from .utils import dataclass_fields_asdict
|
8
|
+
|
9
|
+
|
10
|
+
@dataclass
|
11
|
+
class DetermineNumberOfItems(PositionedDataObjectProperty):
|
12
|
+
|
13
|
+
@staticmethod
|
14
|
+
def from_et(et_element: ElementTree.Element,
|
15
|
+
doc_frags: List[OdxDocFragment]) -> "DetermineNumberOfItems":
|
16
|
+
kwargs = dataclass_fields_asdict(
|
17
|
+
PositionedDataObjectProperty.from_et(et_element, doc_frags))
|
18
|
+
return DetermineNumberOfItems(**kwargs)
|
@@ -9,6 +9,7 @@ from .createanystructure import create_any_structure_from_et
|
|
9
9
|
from .createsdgs import create_sdgs_from_et
|
10
10
|
from .dataobjectproperty import DataObjectProperty
|
11
11
|
from .dtcdop import DtcDop
|
12
|
+
from .dynamiclengthfield import DynamicLengthField
|
12
13
|
from .endofpdufield import EndOfPduField
|
13
14
|
from .environmentdata import EnvironmentData
|
14
15
|
from .environmentdatadescription import EnvironmentDataDescription
|
@@ -31,6 +32,7 @@ class DiagDataDictionarySpec:
|
|
31
32
|
data_object_props: NamedItemList[DataObjectProperty]
|
32
33
|
structures: NamedItemList[BasicStructure]
|
33
34
|
end_of_pdu_fields: NamedItemList[EndOfPduField]
|
35
|
+
dynamic_length_fields: NamedItemList[DynamicLengthField]
|
34
36
|
tables: NamedItemList[Table]
|
35
37
|
env_data_descs: NamedItemList[EnvironmentDataDescription]
|
36
38
|
env_datas: NamedItemList[EnvironmentData]
|
@@ -44,6 +46,7 @@ class DiagDataDictionarySpec:
|
|
44
46
|
self.data_object_props,
|
45
47
|
self.structures,
|
46
48
|
self.end_of_pdu_fields,
|
49
|
+
self.dynamic_length_fields,
|
47
50
|
self.dtc_dops,
|
48
51
|
self.tables,
|
49
52
|
),)
|
@@ -67,6 +70,11 @@ class DiagDataDictionarySpec:
|
|
67
70
|
for eofp_element in et_element.iterfind("END-OF-PDU-FIELDS/END-OF-PDU-FIELD")
|
68
71
|
]
|
69
72
|
|
73
|
+
dynamic_length_fields = [
|
74
|
+
DynamicLengthField.from_et(dl_element, doc_frags)
|
75
|
+
for dl_element in et_element.iterfind("DYNAMIC-LENGTH-FIELDS/DYNAMIC-LENGTH-FIELD")
|
76
|
+
]
|
77
|
+
|
70
78
|
dtc_dops = []
|
71
79
|
for dtc_dop_elem in et_element.iterfind("DTC-DOPS/DTC-DOP"):
|
72
80
|
dtc_dop = DtcDop.from_et(dtc_dop_elem, doc_frags)
|
@@ -123,6 +131,7 @@ class DiagDataDictionarySpec:
|
|
123
131
|
data_object_props=NamedItemList(data_object_props),
|
124
132
|
structures=NamedItemList(structures),
|
125
133
|
end_of_pdu_fields=NamedItemList(end_of_pdu_fields),
|
134
|
+
dynamic_length_fields=NamedItemList(dynamic_length_fields),
|
126
135
|
dtc_dops=NamedItemList(dtc_dops),
|
127
136
|
unit_spec=unit_spec,
|
128
137
|
tables=NamedItemList(tables),
|
@@ -145,6 +154,7 @@ class DiagDataDictionarySpec:
|
|
145
154
|
self.sdgs,
|
146
155
|
self.structures,
|
147
156
|
self.end_of_pdu_fields,
|
157
|
+
self.dynamic_length_fields,
|
148
158
|
self.tables,
|
149
159
|
):
|
150
160
|
odxlinks.update(obj._build_odxlinks())
|
@@ -157,8 +167,8 @@ class DiagDataDictionarySpec:
|
|
157
167
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
158
168
|
|
159
169
|
for obj in chain(self.data_object_props, self.dtc_dops, self.end_of_pdu_fields,
|
160
|
-
self.
|
161
|
-
self.tables):
|
170
|
+
self.dynamic_length_fields, self.env_data_descs, self.env_datas, self.muxs,
|
171
|
+
self.sdgs, self.structures, self.tables):
|
162
172
|
obj._resolve_odxlinks(odxlinks)
|
163
173
|
|
164
174
|
if self.unit_spec is not None:
|
@@ -166,8 +176,8 @@ class DiagDataDictionarySpec:
|
|
166
176
|
|
167
177
|
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
168
178
|
for obj in chain(self.data_object_props, self.dtc_dops, self.end_of_pdu_fields,
|
169
|
-
self.
|
170
|
-
self.tables):
|
179
|
+
self.dynamic_length_fields, self.env_data_descs, self.env_datas, self.muxs,
|
180
|
+
self.sdgs, self.structures, self.tables):
|
171
181
|
obj._resolve_snrefs(diag_layer)
|
172
182
|
|
173
183
|
if self.unit_spec is not None:
|
odxtools/diaglayer.py
CHANGED
@@ -10,24 +10,17 @@ from deprecation import deprecated
|
|
10
10
|
|
11
11
|
from .additionalaudience import AdditionalAudience
|
12
12
|
from .admindata import AdminData
|
13
|
-
from .basicstructure import BasicStructure
|
14
13
|
from .communicationparameterref import CommunicationParameterRef
|
15
14
|
from .companydata import CompanyData
|
16
|
-
from .dataobjectproperty import DataObjectProperty
|
17
15
|
from .diagdatadictionaryspec import DiagDataDictionarySpec
|
18
16
|
from .diaglayerraw import DiagLayerRaw
|
19
17
|
from .diaglayertype import DiagLayerType
|
20
18
|
from .diagservice import DiagService
|
21
|
-
from .dtcdop import DtcDop
|
22
19
|
from .ecuvariantpattern import EcuVariantPattern
|
23
|
-
from .endofpdufield import EndOfPduField
|
24
|
-
from .environmentdata import EnvironmentData
|
25
|
-
from .environmentdatadescription import EnvironmentDataDescription
|
26
20
|
from .exceptions import DecodeError, OdxWarning, odxassert
|
27
21
|
from .functionalclass import FunctionalClass
|
28
22
|
from .message import Message
|
29
|
-
from .
|
30
|
-
from .nameditemlist import NamedItemList
|
23
|
+
from .nameditemlist import NamedItemList, OdxNamed
|
31
24
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
32
25
|
from .parentref import ParentRef
|
33
26
|
from .request import Request
|
@@ -40,6 +33,7 @@ from .unitgroup import UnitGroup
|
|
40
33
|
from .unitspec import UnitSpec
|
41
34
|
|
42
35
|
T = TypeVar("T")
|
36
|
+
TNamed = TypeVar("TNamed", bound=OdxNamed)
|
43
37
|
|
44
38
|
PrefixTree = Dict[int, Union[List[DiagService], "PrefixTree"]]
|
45
39
|
|
@@ -154,47 +148,58 @@ class DiagLayer:
|
|
154
148
|
sdgs=[])
|
155
149
|
############
|
156
150
|
|
157
|
-
dops =
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
151
|
+
dops = self._compute_available_ddd_spec_items(
|
152
|
+
lambda ddd_spec: ddd_spec.data_object_props,
|
153
|
+
lambda parent_ref: parent_ref.not_inherited_dops,
|
154
|
+
)
|
155
|
+
structures = self._compute_available_ddd_spec_items(
|
156
|
+
lambda ddd_spec: ddd_spec.structures,
|
157
|
+
lambda parent_ref: parent_ref.not_inherited_dops,
|
158
|
+
)
|
159
|
+
dtc_dops = self._compute_available_ddd_spec_items(
|
160
|
+
lambda ddd_spec: ddd_spec.dtc_dops,
|
161
|
+
lambda parent_ref: parent_ref.not_inherited_dops,
|
162
|
+
)
|
163
|
+
end_of_pdu_fields = self._compute_available_ddd_spec_items(
|
164
|
+
lambda ddd_spec: ddd_spec.end_of_pdu_fields,
|
165
|
+
lambda parent_ref: parent_ref.not_inherited_dops,
|
166
|
+
)
|
167
|
+
dynamic_length_fields = self._compute_available_ddd_spec_items(
|
168
|
+
lambda ddd_spec: ddd_spec.dynamic_length_fields,
|
169
|
+
lambda parent_ref: parent_ref.not_inherited_dops,
|
170
|
+
)
|
171
|
+
env_data_descs = self._compute_available_ddd_spec_items(
|
172
|
+
lambda ddd_spec: ddd_spec.env_data_descs,
|
173
|
+
lambda parent_ref: parent_ref.not_inherited_dops,
|
174
|
+
)
|
175
|
+
env_datas = self._compute_available_ddd_spec_items(
|
176
|
+
lambda ddd_spec: ddd_spec.env_datas, lambda parent_ref: parent_ref.not_inherited_dops)
|
177
|
+
muxs = self._compute_available_ddd_spec_items(
|
178
|
+
lambda ddd_spec: ddd_spec.muxs, lambda parent_ref: parent_ref.not_inherited_dops)
|
179
|
+
tables = self._compute_available_ddd_spec_items(
|
180
|
+
lambda ddd_spec: ddd_spec.tables, lambda parent_ref: parent_ref.not_inherited_tables)
|
165
181
|
ddds_sdgs: List[SpecialDataGroup]
|
166
182
|
if self.diag_layer_raw.diag_data_dictionary_spec:
|
167
|
-
dtc_dops = self.diag_layer_raw.diag_data_dictionary_spec.dtc_dops
|
168
|
-
structures = self.diag_layer_raw.diag_data_dictionary_spec.structures
|
169
|
-
end_of_pdu_fields = self.diag_layer_raw.diag_data_dictionary_spec.end_of_pdu_fields
|
170
|
-
env_data_descs = self.diag_layer_raw.diag_data_dictionary_spec.env_data_descs
|
171
|
-
env_datas = self.diag_layer_raw.diag_data_dictionary_spec.env_datas
|
172
|
-
muxs = self.diag_layer_raw.diag_data_dictionary_spec.muxs
|
173
183
|
ddds_sdgs = self.diag_layer_raw.diag_data_dictionary_spec.sdgs
|
174
184
|
else:
|
175
|
-
dtc_dops = NamedItemList()
|
176
|
-
structures = NamedItemList()
|
177
|
-
end_of_pdu_fields = NamedItemList()
|
178
|
-
env_data_descs = NamedItemList()
|
179
|
-
env_datas = NamedItemList()
|
180
|
-
muxs = NamedItemList()
|
181
185
|
ddds_sdgs = []
|
182
186
|
|
183
187
|
# create a DiagDataDictionarySpec which includes all the
|
184
188
|
# inherited objects. To me, this seems rather inelegant, but
|
185
189
|
# hey, it's described like this in the standard.
|
186
|
-
self._diag_data_dictionary_spec =
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
190
|
+
self._diag_data_dictionary_spec = DiagDataDictionarySpec(
|
191
|
+
data_object_props=dops,
|
192
|
+
dtc_dops=dtc_dops,
|
193
|
+
structures=structures,
|
194
|
+
end_of_pdu_fields=end_of_pdu_fields,
|
195
|
+
dynamic_length_fields=dynamic_length_fields,
|
196
|
+
tables=tables,
|
197
|
+
env_data_descs=env_data_descs,
|
198
|
+
env_datas=env_datas,
|
199
|
+
muxs=muxs,
|
200
|
+
unit_spec=unit_spec,
|
201
|
+
sdgs=ddds_sdgs,
|
202
|
+
)
|
198
203
|
|
199
204
|
#####
|
200
205
|
# compute the communication parameters applicable to the
|
@@ -457,29 +462,19 @@ class DiagLayer:
|
|
457
462
|
|
458
463
|
return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
|
459
464
|
|
460
|
-
def
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
return dl.diag_layer_raw.diag_data_dictionary_spec.data_object_props
|
466
|
-
|
467
|
-
def not_inherited_fn(parent_ref):
|
468
|
-
return parent_ref.not_inherited_dops
|
469
|
-
|
470
|
-
return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
|
471
|
-
|
472
|
-
def _compute_available_tables(self) -> Iterable[Table]:
|
465
|
+
def _compute_available_ddd_spec_items(
|
466
|
+
self,
|
467
|
+
include: Callable[[DiagDataDictionarySpec], Iterable[TNamed]],
|
468
|
+
exclude: Callable[["ParentRef"], List[str]],
|
469
|
+
) -> NamedItemList[TNamed]:
|
473
470
|
|
474
|
-
def get_local_objects_fn(dl):
|
471
|
+
def get_local_objects_fn(dl: "DiagLayer"):
|
475
472
|
if dl.diag_layer_raw.diag_data_dictionary_spec is None:
|
476
473
|
return []
|
477
|
-
return dl.diag_layer_raw.diag_data_dictionary_spec
|
474
|
+
return include(dl.diag_layer_raw.diag_data_dictionary_spec)
|
478
475
|
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
|
476
|
+
found = self._compute_available_objects(get_local_objects_fn, exclude)
|
477
|
+
return NamedItemList(found)
|
483
478
|
|
484
479
|
def _compute_available_functional_classes(self) -> Iterable[FunctionalClass]:
|
485
480
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import TYPE_CHECKING, Any, Dict, List
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from .decodestate import DecodeState
|
7
|
+
from .determinenumberofitems import DetermineNumberOfItems
|
8
|
+
from .encodestate import EncodeState
|
9
|
+
from .exceptions import odxrequire
|
10
|
+
from .field import Field
|
11
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
12
|
+
from .odxtypes import ParameterValueDict
|
13
|
+
from .utils import dataclass_fields_asdict
|
14
|
+
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
from .diaglayer import DiagLayer
|
17
|
+
|
18
|
+
|
19
|
+
@dataclass
|
20
|
+
class DynamicLengthField(Field):
|
21
|
+
"""Array of structure with length field"""
|
22
|
+
offset: int
|
23
|
+
determine_number_of_items: DetermineNumberOfItems
|
24
|
+
|
25
|
+
@staticmethod
|
26
|
+
def from_et(et_element: ElementTree.Element,
|
27
|
+
doc_frags: List[OdxDocFragment]) -> "DynamicLengthField":
|
28
|
+
kwargs = dataclass_fields_asdict(Field.from_et(et_element, doc_frags))
|
29
|
+
offset = int(odxrequire(et_element.findtext('OFFSET')))
|
30
|
+
determine_number_of_items = DetermineNumberOfItems.from_et(
|
31
|
+
odxrequire(et_element.find('DETERMINE-NUMBER-OF-ITEMS')),
|
32
|
+
doc_frags,
|
33
|
+
)
|
34
|
+
return DynamicLengthField(
|
35
|
+
offset=offset, determine_number_of_items=determine_number_of_items, **kwargs)
|
36
|
+
|
37
|
+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
38
|
+
odxlinks = super()._build_odxlinks()
|
39
|
+
odxlinks.update(self.determine_number_of_items._build_odxlinks())
|
40
|
+
return odxlinks
|
41
|
+
|
42
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
43
|
+
super()._resolve_odxlinks(odxlinks)
|
44
|
+
self.determine_number_of_items._resolve_odxlinks(odxlinks)
|
45
|
+
|
46
|
+
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
47
|
+
super()._resolve_snrefs(diag_layer)
|
48
|
+
self.determine_number_of_items._resolve_snrefs(diag_layer)
|
49
|
+
|
50
|
+
def convert_physical_to_bytes(
|
51
|
+
self,
|
52
|
+
physical_value: List[ParameterValueDict],
|
53
|
+
encode_state: EncodeState,
|
54
|
+
bit_position: int = 0,
|
55
|
+
) -> bytes:
|
56
|
+
raise NotImplementedError()
|
57
|
+
|
58
|
+
def convert_bytes_to_physical(self, decode_state: DecodeState, bit_position: int = 0):
|
59
|
+
raise NotImplementedError()
|
odxtools/element.py
CHANGED
@@ -2,11 +2,9 @@ from dataclasses import dataclass
|
|
2
2
|
from typing import List, Optional
|
3
3
|
from xml.etree import ElementTree
|
4
4
|
|
5
|
-
from
|
6
|
-
from odxtools.utils import create_description_from_et
|
7
|
-
|
5
|
+
from .exceptions import odxrequire
|
8
6
|
from .odxlink import OdxDocFragment, OdxLinkId
|
9
|
-
from .utils import dataclass_fields_asdict
|
7
|
+
from .utils import create_description_from_et, dataclass_fields_asdict
|
10
8
|
|
11
9
|
|
12
10
|
@dataclass
|
odxtools/endofpdufield.py
CHANGED
@@ -1,62 +1,28 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from copy import copy
|
3
3
|
from dataclasses import dataclass
|
4
|
-
from typing import
|
4
|
+
from typing import List, Optional
|
5
5
|
from xml.etree import ElementTree
|
6
6
|
|
7
|
-
from .basicstructure import BasicStructure
|
8
|
-
from .createsdgs import create_sdgs_from_et
|
9
7
|
from .decodestate import DecodeState
|
10
|
-
from .dopbase import DopBase
|
11
|
-
from .element import IdentifiableElement
|
12
8
|
from .encodestate import EncodeState
|
13
9
|
from .exceptions import odxassert
|
14
|
-
from .
|
15
|
-
from .
|
10
|
+
from .field import Field
|
11
|
+
from .odxlink import OdxDocFragment
|
12
|
+
from .odxtypes import ParameterValueDict
|
16
13
|
from .utils import dataclass_fields_asdict
|
17
14
|
|
18
|
-
if TYPE_CHECKING:
|
19
|
-
from .diaglayer import DiagLayer
|
20
|
-
|
21
15
|
|
22
16
|
@dataclass
|
23
|
-
class EndOfPduField(
|
17
|
+
class EndOfPduField(Field):
|
24
18
|
"""End of PDU fields are structures that are repeated until the end of the PDU"""
|
25
|
-
|
26
|
-
structure_ref: Optional[OdxLinkRef]
|
27
|
-
structure_snref: Optional[str]
|
28
|
-
env_data_desc_ref: Optional[OdxLinkRef]
|
29
|
-
env_data_desc_snref: Optional[str]
|
30
19
|
min_number_of_items: Optional[int]
|
31
20
|
max_number_of_items: Optional[int]
|
32
21
|
|
33
|
-
def __post_init__(self) -> None:
|
34
|
-
num_struct_refs = 0 if self.structure_ref is None else 1
|
35
|
-
num_struct_refs += 0 if self.structure_snref is None else 1
|
36
|
-
|
37
|
-
num_edd_refs = 0 if self.env_data_desc_ref is None else 1
|
38
|
-
num_edd_refs += 0 if self.env_data_desc_snref is None else 1
|
39
|
-
|
40
|
-
odxassert(
|
41
|
-
num_struct_refs + num_edd_refs == 1,
|
42
|
-
"END-OF-PDU-FIELDs need to specify exactly one reference to a "
|
43
|
-
"structure or an environment data description")
|
44
|
-
|
45
22
|
@staticmethod
|
46
23
|
def from_et(et_element: ElementTree.Element,
|
47
24
|
doc_frags: List[OdxDocFragment]) -> "EndOfPduField":
|
48
|
-
kwargs = dataclass_fields_asdict(
|
49
|
-
sdgs = create_sdgs_from_et(et_element.find("SDGS"), doc_frags)
|
50
|
-
|
51
|
-
structure_ref = OdxLinkRef.from_et(et_element.find("BASIC-STRUCTURE-REF"), doc_frags)
|
52
|
-
structure_snref = None
|
53
|
-
if (edsnr_elem := et_element.find("BASIC-STRUCTURE-SNREF")) is not None:
|
54
|
-
structure_snref = edsnr_elem.get("SHORT-NAME")
|
55
|
-
|
56
|
-
env_data_desc_ref = OdxLinkRef.from_et(et_element.find("ENV-DATA-DESC-REF"), doc_frags)
|
57
|
-
env_data_desc_snref = None
|
58
|
-
if (edsnr_elem := et_element.find("ENV-DATA-DESC-SNREF")) is not None:
|
59
|
-
env_data_desc_snref = edsnr_elem.get("SHORT-NAME")
|
25
|
+
kwargs = dataclass_fields_asdict(Field.from_et(et_element, doc_frags))
|
60
26
|
|
61
27
|
if (min_n_str := et_element.findtext("MIN-NUMBER-OF-ITEMS")) is not None:
|
62
28
|
min_number_of_items = int(min_n_str)
|
@@ -67,32 +33,13 @@ class EndOfPduField(DopBase):
|
|
67
33
|
else:
|
68
34
|
max_number_of_items = None
|
69
35
|
|
70
|
-
is_visible_raw = odxstr_to_bool(et_element.get("IS-VISIBLE"))
|
71
36
|
eopf = EndOfPduField(
|
72
|
-
sdgs=sdgs,
|
73
|
-
structure_ref=structure_ref,
|
74
|
-
structure_snref=structure_snref,
|
75
|
-
env_data_desc_ref=env_data_desc_ref,
|
76
|
-
env_data_desc_snref=env_data_desc_snref,
|
77
37
|
min_number_of_items=min_number_of_items,
|
78
38
|
max_number_of_items=max_number_of_items,
|
79
|
-
is_visible_raw=is_visible_raw,
|
80
39
|
**kwargs)
|
81
40
|
|
82
41
|
return eopf
|
83
42
|
|
84
|
-
@property
|
85
|
-
def structure(self) -> "BasicStructure":
|
86
|
-
"""may be a Structure or a env-data-desc"""
|
87
|
-
return self._structure
|
88
|
-
|
89
|
-
@property
|
90
|
-
def bit_length(self):
|
91
|
-
return self.structure.bit_length
|
92
|
-
|
93
|
-
def convert_physical_to_internal(self, physical_value):
|
94
|
-
return self.structure.convert_physical_to_internal(physical_value)
|
95
|
-
|
96
43
|
def convert_physical_to_bytes(
|
97
44
|
self,
|
98
45
|
physical_value: ParameterValueDict,
|
@@ -133,21 +80,3 @@ class EndOfPduField(DopBase):
|
|
133
80
|
value.append(new_value)
|
134
81
|
|
135
82
|
return value, next_byte_position
|
136
|
-
|
137
|
-
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
138
|
-
"""Recursively resolve any odxlinks references"""
|
139
|
-
if self.structure_ref is not None:
|
140
|
-
self._structure = odxlinks.resolve(self.structure_ref)
|
141
|
-
|
142
|
-
if self.env_data_desc_ref is not None:
|
143
|
-
self._env_data_desc = odxlinks.resolve(self.env_data_desc_ref)
|
144
|
-
|
145
|
-
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
146
|
-
"""Recursively resolve any short-name references"""
|
147
|
-
if self.structure_snref is not None:
|
148
|
-
structures = diag_layer.diag_data_dictionary_spec.structures
|
149
|
-
self._structure = structures[self.structure_snref]
|
150
|
-
|
151
|
-
if self.env_data_desc_snref is not None:
|
152
|
-
env_data_descs = diag_layer.diag_data_dictionary_spec.env_data_descs
|
153
|
-
self._env_data_desc = env_data_descs[self.env_data_desc_snref]
|
odxtools/field.py
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import TYPE_CHECKING, List, Optional
|
3
|
+
from xml.etree import ElementTree
|
4
|
+
|
5
|
+
from .environmentdatadescription import EnvironmentDataDescription
|
6
|
+
from .basicstructure import BasicStructure
|
7
|
+
from .createsdgs import create_sdgs_from_et
|
8
|
+
from .dopbase import DopBase
|
9
|
+
from .element import IdentifiableElement
|
10
|
+
from .exceptions import odxassert, odxrequire
|
11
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkRef
|
12
|
+
from .odxtypes import odxstr_to_bool
|
13
|
+
from .utils import dataclass_fields_asdict
|
14
|
+
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
from .diaglayer import DiagLayer
|
17
|
+
|
18
|
+
|
19
|
+
@dataclass
|
20
|
+
class Field(DopBase):
|
21
|
+
structure_ref: Optional[OdxLinkRef]
|
22
|
+
structure_snref: Optional[str]
|
23
|
+
env_data_desc_ref: Optional[OdxLinkRef]
|
24
|
+
env_data_desc_snref: Optional[str]
|
25
|
+
|
26
|
+
def __post_init__(self) -> None:
|
27
|
+
self._structure: Optional[BasicStructure] = None
|
28
|
+
self._env_data_desc: Optional[EnvironmentDataDescription] = None
|
29
|
+
num_struct_refs = 0 if self.structure_ref is None else 1
|
30
|
+
num_struct_refs += 0 if self.structure_snref is None else 1
|
31
|
+
|
32
|
+
num_edd_refs = 0 if self.env_data_desc_ref is None else 1
|
33
|
+
num_edd_refs += 0 if self.env_data_desc_snref is None else 1
|
34
|
+
|
35
|
+
odxassert(
|
36
|
+
num_struct_refs + num_edd_refs == 1,
|
37
|
+
"FIELDs need to specify exactly one reference to a "
|
38
|
+
"structure or an environment data description")
|
39
|
+
|
40
|
+
@staticmethod
|
41
|
+
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Field":
|
42
|
+
kwargs = dataclass_fields_asdict(DopBase.from_et(et_element, doc_frags))
|
43
|
+
sdgs = create_sdgs_from_et(et_element.find("SDGS"), doc_frags)
|
44
|
+
|
45
|
+
structure_ref = OdxLinkRef.from_et(et_element.find("BASIC-STRUCTURE-REF"), doc_frags)
|
46
|
+
structure_snref = None
|
47
|
+
if (edsnr_elem := et_element.find("BASIC-STRUCTURE-SNREF")) is not None:
|
48
|
+
structure_snref = edsnr_elem.get("SHORT-NAME")
|
49
|
+
|
50
|
+
env_data_desc_ref = OdxLinkRef.from_et(et_element.find("ENV-DATA-DESC-REF"), doc_frags)
|
51
|
+
env_data_desc_snref = None
|
52
|
+
if (edsnr_elem := et_element.find("ENV-DATA-DESC-SNREF")) is not None:
|
53
|
+
env_data_desc_snref = edsnr_elem.get("SHORT-NAME")
|
54
|
+
|
55
|
+
is_visible_raw = odxstr_to_bool(et_element.get("IS-VISIBLE"))
|
56
|
+
return Field(
|
57
|
+
sdgs=sdgs,
|
58
|
+
structure_ref=structure_ref,
|
59
|
+
structure_snref=structure_snref,
|
60
|
+
env_data_desc_ref=env_data_desc_ref,
|
61
|
+
env_data_desc_snref=env_data_desc_snref,
|
62
|
+
is_visible_raw=is_visible_raw,
|
63
|
+
**kwargs)
|
64
|
+
|
65
|
+
@property
|
66
|
+
def structure(self) -> BasicStructure:
|
67
|
+
"""may be a Structure or a env-data-desc"""
|
68
|
+
return odxrequire(self._structure, "EnvironmentDataDescription is not supported")
|
69
|
+
|
70
|
+
@property
|
71
|
+
def bit_length(self):
|
72
|
+
return self.structure.bit_length
|
73
|
+
|
74
|
+
def convert_physical_to_internal(self, physical_value):
|
75
|
+
return self.structure.convert_physical_to_internal(physical_value)
|
76
|
+
|
77
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
78
|
+
"""Recursively resolve any odxlinks references"""
|
79
|
+
if self.structure_ref is not None:
|
80
|
+
self._structure = odxlinks.resolve(self.structure_ref, BasicStructure)
|
81
|
+
|
82
|
+
if self.env_data_desc_ref is not None:
|
83
|
+
self._env_data_desc = odxlinks.resolve(self.env_data_desc_ref,
|
84
|
+
EnvironmentDataDescription)
|
85
|
+
|
86
|
+
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
87
|
+
"""Recursively resolve any short-name references"""
|
88
|
+
if self.structure_snref is not None:
|
89
|
+
structures = diag_layer.diag_data_dictionary_spec.structures
|
90
|
+
self._structure = odxrequire(structures.get(self.structure_snref))
|
91
|
+
|
92
|
+
if self.env_data_desc_snref is not None:
|
93
|
+
env_data_descs = diag_layer.diag_data_dictionary_spec.env_data_descs
|
94
|
+
self._env_data_desc = odxrequire(env_data_descs.get(self.env_data_desc_snref))
|
odxtools/multiplexer.py
CHANGED
@@ -63,7 +63,7 @@ class Multiplexer(DopBase):
|
|
63
63
|
return None
|
64
64
|
|
65
65
|
def _get_case_limits(self, case: MultiplexerCase):
|
66
|
-
key_type = self.switch_key.
|
66
|
+
key_type = self.switch_key.dop.physical_type.base_data_type
|
67
67
|
lower_limit = key_type.make_from(case.lower_limit)
|
68
68
|
upper_limit = key_type.make_from(case.upper_limit)
|
69
69
|
return lower_limit, upper_limit
|
@@ -80,7 +80,6 @@ class Multiplexer(DopBase):
|
|
80
80
|
with only one key equal to the desired case""")
|
81
81
|
|
82
82
|
case_name, case_value = next(iter(physical_value.items()))
|
83
|
-
key_pos = self.switch_key.byte_position
|
84
83
|
case_pos = self.byte_position
|
85
84
|
|
86
85
|
for case in self.cases or []:
|
@@ -92,14 +91,11 @@ class Multiplexer(DopBase):
|
|
92
91
|
case_bytes = bytes()
|
93
92
|
|
94
93
|
key_value, _ = self._get_case_limits(case)
|
95
|
-
|
96
|
-
sk_bit_position = sk_bit_position if sk_bit_position is not None else 0
|
97
|
-
key_bytes = self.switch_key._dop.convert_physical_to_bytes(
|
98
|
-
key_value, encode_state, sk_bit_position)
|
94
|
+
key_bytes = self.switch_key.convert_physical_to_bytes(key_value, encode_state)
|
99
95
|
|
100
|
-
mux_len = max(len(key_bytes)
|
96
|
+
mux_len = max(len(key_bytes), len(case_bytes) + case_pos)
|
101
97
|
mux_bytes = bytearray(mux_len)
|
102
|
-
mux_bytes[
|
98
|
+
mux_bytes[:len(key_bytes)] = key_bytes
|
103
99
|
mux_bytes[case_pos:case_pos + len(case_bytes)] = case_bytes
|
104
100
|
|
105
101
|
return bytes(mux_bytes)
|
@@ -111,17 +107,9 @@ class Multiplexer(DopBase):
|
|
111
107
|
if bit_position != 0:
|
112
108
|
raise DecodeError("Multiplexer must be aligned, i.e. bit_position=0, but "
|
113
109
|
f"{self.short_name} was passed the bit position {bit_position}")
|
114
|
-
|
115
|
-
key_decode_state = DecodeState(
|
116
|
-
coded_message=byte_code[self.switch_key.byte_position:],
|
117
|
-
parameter_values=dict(),
|
118
|
-
next_byte_position=0,
|
119
|
-
)
|
120
|
-
bit_position_int = (
|
121
|
-
self.switch_key.bit_position if self.switch_key.bit_position is not None else 0)
|
122
|
-
key_value, key_next_byte = self.switch_key._dop.convert_bytes_to_physical(
|
123
|
-
key_decode_state, bit_position=bit_position_int)
|
110
|
+
key_value, key_next_byte = self.switch_key.convert_bytes_to_physical(decode_state)
|
124
111
|
|
112
|
+
byte_code = decode_state.coded_message[decode_state.next_byte_position:]
|
125
113
|
case_decode_state = DecodeState(
|
126
114
|
coded_message=byte_code[self.byte_position:],
|
127
115
|
parameter_values=dict(),
|
odxtools/multiplexerswitchkey.py
CHANGED
@@ -1,53 +1,18 @@
|
|
1
|
-
# SPDX-License-Identifier: MIT
|
2
1
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
2
|
+
from typing import List
|
4
3
|
from xml.etree import ElementTree
|
5
4
|
|
6
|
-
from .
|
7
|
-
from .
|
8
|
-
from .
|
9
|
-
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
10
|
-
|
11
|
-
if TYPE_CHECKING:
|
12
|
-
from .diaglayer import DiagLayer
|
5
|
+
from .odxlink import OdxDocFragment
|
6
|
+
from .positioneddataobjectproperty import PositionedDataObjectProperty
|
7
|
+
from .utils import dataclass_fields_asdict
|
13
8
|
|
14
9
|
|
15
10
|
@dataclass
|
16
|
-
class MultiplexerSwitchKey:
|
17
|
-
"""This class represents a Switch Key, which is used to select one of the cases defined in the Multiplexer."""
|
18
|
-
|
19
|
-
byte_position: int
|
20
|
-
bit_position: Optional[int]
|
21
|
-
dop_ref: OdxLinkRef
|
22
|
-
|
23
|
-
def __post_init__(self):
|
24
|
-
self._dop: DataObjectProperty = None # type: ignore
|
11
|
+
class MultiplexerSwitchKey(PositionedDataObjectProperty):
|
25
12
|
|
26
13
|
@staticmethod
|
27
14
|
def from_et(et_element: ElementTree.Element,
|
28
15
|
doc_frags: List[OdxDocFragment]) -> "MultiplexerSwitchKey":
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
bit_position = int(bit_position_str) if bit_position_str is not None else None
|
33
|
-
dop_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DATA-OBJECT-PROP-REF"), doc_frags))
|
34
|
-
|
35
|
-
return MultiplexerSwitchKey(
|
36
|
-
byte_position=byte_position,
|
37
|
-
bit_position=bit_position,
|
38
|
-
dop_ref=dop_ref,
|
39
|
-
)
|
40
|
-
|
41
|
-
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
42
|
-
return {}
|
43
|
-
|
44
|
-
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
45
|
-
dop = odxlinks.resolve(self.dop_ref)
|
46
|
-
if isinstance(dop, DataObjectProperty):
|
47
|
-
self._dop = dop
|
48
|
-
else:
|
49
|
-
logger.warning(
|
50
|
-
f"DATA-OBJECT-PROP-REF '{self.dop_ref}' could not be resolved in SWITCH-KEY.")
|
51
|
-
|
52
|
-
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
53
|
-
pass
|
16
|
+
kwargs = dataclass_fields_asdict(
|
17
|
+
PositionedDataObjectProperty.from_et(et_element, doc_frags))
|
18
|
+
return MultiplexerSwitchKey(**kwargs)
|
odxtools/odxtypes.py
CHANGED
@@ -6,7 +6,7 @@ from xml.etree import ElementTree
|
|
6
6
|
from .exceptions import odxassert, odxraise, odxrequire
|
7
7
|
|
8
8
|
if TYPE_CHECKING:
|
9
|
-
from
|
9
|
+
from .parameters.parameter import Parameter
|
10
10
|
|
11
11
|
|
12
12
|
def bytefield_to_bytearray(bytefield: str) -> bytearray:
|