odxtools 9.2.0__py3-none-any.whl → 9.4.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.
- odxtools/companyrevisioninfo.py +1 -1
- odxtools/comparaminstance.py +1 -6
- odxtools/comparamspec.py +3 -2
- odxtools/comparamsubset.py +3 -5
- odxtools/dataobjectproperty.py +12 -6
- odxtools/decodestate.py +120 -26
- odxtools/description.py +19 -2
- odxtools/diagcodedtype.py +9 -2
- odxtools/diagcomm.py +4 -4
- odxtools/diaglayercontainer.py +2 -2
- odxtools/diaglayers/diaglayerraw.py +2 -2
- odxtools/diaglayers/hierarchyelement.py +2 -0
- odxtools/diagnostictroublecode.py +4 -8
- odxtools/diagservice.py +70 -4
- odxtools/diagvariable.py +45 -7
- odxtools/encodestate.py +147 -51
- odxtools/encoding.py +56 -0
- odxtools/environmentdatadescription.py +77 -47
- odxtools/functionalclass.py +7 -2
- odxtools/inputparam.py +9 -3
- odxtools/leadinglengthinfotype.py +4 -0
- odxtools/minmaxlengthtype.py +57 -36
- odxtools/modification.py +3 -2
- odxtools/odxcategory.py +2 -2
- odxtools/odxlink.py +31 -7
- odxtools/odxtypes.py +1 -1
- odxtools/outputparam.py +8 -3
- odxtools/parameters/matchingrequestparameter.py +1 -0
- odxtools/parameters/physicalconstantparameter.py +1 -0
- odxtools/parameters/reservedparameter.py +1 -0
- odxtools/parameters/tableentryparameter.py +15 -4
- odxtools/parameters/tablekeyparameter.py +20 -17
- odxtools/paramlengthinfotype.py +5 -3
- odxtools/physicaltype.py +2 -1
- odxtools/scaleconstr.py +4 -4
- odxtools/standardlengthtype.py +98 -22
- odxtools/statetransition.py +24 -3
- odxtools/structure.py +10 -2
- odxtools/swvariable.py +3 -1
- odxtools/table.py +55 -3
- odxtools/tablerow.py +91 -8
- odxtools/templates/macros/printDOP.xml.jinja2 +2 -2
- odxtools/templates/macros/printDescription.xml.jinja2 +5 -1
- odxtools/templates/macros/printDiagLayer.xml.jinja2 +1 -1
- odxtools/templates/macros/printDiagVariable.xml.jinja2 +12 -3
- odxtools/templates/macros/printFunctionalClass.xml.jinja2 +4 -0
- odxtools/templates/macros/printParentRef.xml.jinja2 +27 -0
- odxtools/templates/macros/printProtocol.xml.jinja2 +1 -1
- odxtools/templates/macros/printService.xml.jinja2 +30 -0
- odxtools/templates/macros/printStructure.xml.jinja2 +2 -1
- odxtools/templates/macros/printTable.xml.jinja2 +43 -0
- odxtools/templates/macros/printUnitSpec.xml.jinja2 +4 -0
- odxtools/uds.py +2 -2
- odxtools/unit.py +8 -12
- odxtools/unitspec.py +5 -2
- odxtools/utils.py +44 -1
- odxtools/version.py +2 -2
- {odxtools-9.2.0.dist-info → odxtools-9.4.0.dist-info}/METADATA +2 -2
- {odxtools-9.2.0.dist-info → odxtools-9.4.0.dist-info}/RECORD +63 -62
- {odxtools-9.2.0.dist-info → odxtools-9.4.0.dist-info}/WHEEL +1 -1
- {odxtools-9.2.0.dist-info → odxtools-9.4.0.dist-info}/LICENSE +0 -0
- {odxtools-9.2.0.dist-info → odxtools-9.4.0.dist-info}/entry_points.txt +0 -0
- {odxtools-9.2.0.dist-info → odxtools-9.4.0.dist-info}/top_level.txt +0 -0
odxtools/standardlengthtype.py
CHANGED
@@ -3,7 +3,7 @@ from dataclasses import dataclass
|
|
3
3
|
from typing import List, Literal, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
-
from typing_extensions import override
|
6
|
+
from typing_extensions import SupportsBytes, override
|
7
7
|
|
8
8
|
from .decodestate import DecodeState
|
9
9
|
from .diagcodedtype import DctType, DiagCodedType
|
@@ -59,7 +59,7 @@ class StandardLengthType(DiagCodedType):
|
|
59
59
|
'Can not apply a bit_mask on a value of type {self.base_data_type}',
|
60
60
|
)
|
61
61
|
|
62
|
-
def
|
62
|
+
def __get_used_mask(self, internal_value: AtomicOdxType) -> Optional[bytes]:
|
63
63
|
"""Returns a byte field where all bits that are used by the
|
64
64
|
DiagCoded type are set and all unused ones are not set.
|
65
65
|
|
@@ -68,10 +68,6 @@ class StandardLengthType(DiagCodedType):
|
|
68
68
|
if self.bit_mask is None:
|
69
69
|
return None
|
70
70
|
|
71
|
-
if self.is_condensed:
|
72
|
-
odxraise("Condensed bit masks are not yet supported", NotImplementedError)
|
73
|
-
return
|
74
|
-
|
75
71
|
endianness: Literal["little", "big"] = "big"
|
76
72
|
if not self.is_highlow_byte_order and self.base_data_type in [
|
77
73
|
DataType.A_INT32, DataType.A_UINT32, DataType.A_FLOAT32, DataType.A_FLOAT64
|
@@ -82,52 +78,132 @@ class StandardLengthType(DiagCodedType):
|
|
82
78
|
# been anticipated by the standard, though...
|
83
79
|
endianness = "little"
|
84
80
|
|
81
|
+
if self.is_condensed:
|
82
|
+
# if a condensed bitmask is specified, the number of bits
|
83
|
+
# set to one in the bit mask are used in the PDU
|
84
|
+
|
85
|
+
# TODO: this is pretty slow. replace it by
|
86
|
+
# `self.bit_mask.bit_count()` once we require python >=
|
87
|
+
# 3.10.
|
88
|
+
bit_sz = bin(self.bit_mask).count("1")
|
89
|
+
used_mask = (1 << bit_sz) - 1
|
90
|
+
|
91
|
+
return used_mask.to_bytes((bit_sz + 7) // 8, endianness)
|
92
|
+
|
85
93
|
sz: int
|
86
|
-
if isinstance(internal_value, (
|
87
|
-
sz = len(internal_value)
|
94
|
+
if isinstance(internal_value, (bytearray, SupportsBytes)):
|
95
|
+
sz = len(bytes(internal_value))
|
88
96
|
else:
|
89
97
|
sz = (odxrequire(self.get_static_bit_length()) + 7) // 8
|
90
98
|
|
91
99
|
max_value = (1 << (sz * 8)) - 1
|
92
|
-
|
100
|
+
used_mask = self.bit_mask & max_value
|
93
101
|
|
94
|
-
return
|
102
|
+
return used_mask.to_bytes(sz, endianness)
|
95
103
|
|
96
104
|
def __apply_mask(self, internal_value: AtomicOdxType) -> AtomicOdxType:
|
97
105
|
if self.bit_mask is None:
|
98
106
|
return internal_value
|
107
|
+
|
99
108
|
if self.is_condensed:
|
100
|
-
|
101
|
-
|
109
|
+
int_value: int
|
110
|
+
if isinstance(internal_value, (bytearray, SupportsBytes)):
|
111
|
+
int_value = int.from_bytes(internal_value, 'big')
|
112
|
+
elif isinstance(internal_value, int):
|
113
|
+
int_value = internal_value
|
114
|
+
else:
|
115
|
+
odxraise("bit masks can only be specified for integers and byte fields")
|
116
|
+
return None
|
117
|
+
|
118
|
+
result = 0
|
119
|
+
mask_bit = 0
|
120
|
+
result_bit = 0
|
121
|
+
|
122
|
+
while self.bit_mask >= (1 << mask_bit):
|
123
|
+
if self.bit_mask & (1 << mask_bit):
|
124
|
+
result |= ((int_value & (1 << mask_bit)) >> mask_bit) << result_bit
|
125
|
+
result_bit += 1
|
126
|
+
|
127
|
+
mask_bit += 1
|
128
|
+
|
129
|
+
if isinstance(internal_value, (bytearray, SupportsBytes)):
|
130
|
+
return result.to_bytes(len(internal_value), 'big')
|
131
|
+
|
132
|
+
return result
|
133
|
+
|
102
134
|
if isinstance(internal_value, int):
|
103
135
|
return internal_value & self.bit_mask
|
104
|
-
if isinstance(internal_value,
|
136
|
+
if isinstance(internal_value, (bytearray, SupportsBytes)):
|
105
137
|
int_value = int.from_bytes(internal_value, 'big')
|
106
|
-
int_value
|
107
|
-
return int_value.to_bytes(len(internal_value), 'big')
|
138
|
+
int_value &= self.bit_mask
|
139
|
+
return int_value.to_bytes(len(bytes(internal_value)), 'big')
|
108
140
|
|
109
141
|
odxraise(f'Can not apply a bit_mask on a value of type {type(internal_value)}')
|
110
142
|
return internal_value
|
111
143
|
|
144
|
+
def __unapply_mask(self, raw_value: AtomicOdxType) -> AtomicOdxType:
|
145
|
+
if self.bit_mask is None:
|
146
|
+
return raw_value
|
147
|
+
if self.is_condensed:
|
148
|
+
int_value: int
|
149
|
+
if isinstance(raw_value, (bytearray, SupportsBytes)):
|
150
|
+
int_value = int.from_bytes(raw_value, 'big')
|
151
|
+
elif isinstance(raw_value, int):
|
152
|
+
int_value = raw_value
|
153
|
+
else:
|
154
|
+
odxraise("bit masks can only be specified for integers and byte fields")
|
155
|
+
return None
|
156
|
+
|
157
|
+
result = 0
|
158
|
+
mask_bit = 0
|
159
|
+
input_bit = 0
|
160
|
+
while self.bit_mask >= (1 << mask_bit):
|
161
|
+
if self.bit_mask & (1 << mask_bit):
|
162
|
+
result |= ((int_value & (1 << input_bit)) >> input_bit) << mask_bit
|
163
|
+
input_bit += 1
|
164
|
+
|
165
|
+
mask_bit += 1
|
166
|
+
|
167
|
+
if isinstance(raw_value, (bytearray, SupportsBytes)):
|
168
|
+
return result.to_bytes(len(raw_value), 'big')
|
169
|
+
|
170
|
+
return result
|
171
|
+
if isinstance(raw_value, int):
|
172
|
+
return raw_value & self.bit_mask
|
173
|
+
if isinstance(raw_value, (bytearray, SupportsBytes)):
|
174
|
+
int_value = int.from_bytes(raw_value, 'big')
|
175
|
+
int_value &= self.bit_mask
|
176
|
+
return int_value
|
177
|
+
|
178
|
+
odxraise(f'Can not apply a bit_mask on a value of type {type(raw_value)}')
|
179
|
+
return raw_value
|
180
|
+
|
112
181
|
def get_static_bit_length(self) -> Optional[int]:
|
182
|
+
if self.bit_mask is not None and self.is_condensed:
|
183
|
+
# TODO: this is pretty slow. replace it by
|
184
|
+
# `self.bit_mask.bit_count()` once we require python >=
|
185
|
+
# 3.10.
|
186
|
+
return bin(self.bit_mask).count("1")
|
187
|
+
|
113
188
|
return self.bit_length
|
114
189
|
|
115
190
|
@override
|
116
191
|
def encode_into_pdu(self, internal_value: AtomicOdxType, encode_state: EncodeState) -> None:
|
117
192
|
encode_state.emplace_atomic_value(
|
118
193
|
internal_value=self.__apply_mask(internal_value),
|
119
|
-
used_mask=self.
|
194
|
+
used_mask=self.__get_used_mask(internal_value),
|
120
195
|
bit_length=self.bit_length,
|
121
196
|
base_data_type=self.base_data_type,
|
197
|
+
base_type_encoding=self.base_type_encoding,
|
122
198
|
is_highlow_byte_order=self.is_highlow_byte_order)
|
123
199
|
|
124
200
|
@override
|
125
201
|
def decode_from_pdu(self, decode_state: DecodeState) -> AtomicOdxType:
|
126
|
-
|
127
|
-
self.bit_length,
|
128
|
-
self.base_data_type,
|
129
|
-
self.
|
130
|
-
|
131
|
-
internal_value = self.
|
202
|
+
raw_value = decode_state.extract_atomic_value(
|
203
|
+
bit_length=self.bit_length,
|
204
|
+
base_data_type=self.base_data_type,
|
205
|
+
base_type_encoding=self.base_type_encoding,
|
206
|
+
is_highlow_byte_order=self.is_highlow_byte_order)
|
207
|
+
internal_value = self.__unapply_mask(raw_value)
|
132
208
|
|
133
209
|
return internal_value
|
odxtools/statetransition.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import Any, Dict, List
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .element import IdentifiableElement
|
@@ -11,6 +11,20 @@ from .state import State
|
|
11
11
|
from .utils import dataclass_fields_asdict
|
12
12
|
|
13
13
|
|
14
|
+
@dataclass
|
15
|
+
class ExternalAccessMethod(IdentifiableElement):
|
16
|
+
method: str
|
17
|
+
|
18
|
+
@staticmethod
|
19
|
+
def from_et(et_element: ElementTree.Element,
|
20
|
+
doc_frags: List[OdxDocFragment]) -> "ExternalAccessMethod":
|
21
|
+
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
22
|
+
|
23
|
+
method = odxrequire(et_element.findtext("METHOD"))
|
24
|
+
|
25
|
+
return ExternalAccessMethod(method=method, **kwargs)
|
26
|
+
|
27
|
+
|
14
28
|
@dataclass
|
15
29
|
class StateTransition(IdentifiableElement):
|
16
30
|
"""
|
@@ -18,7 +32,7 @@ class StateTransition(IdentifiableElement):
|
|
18
32
|
"""
|
19
33
|
source_snref: str
|
20
34
|
target_snref: str
|
21
|
-
|
35
|
+
external_access_method: Optional[ExternalAccessMethod]
|
22
36
|
|
23
37
|
@property
|
24
38
|
def source_state(self) -> State:
|
@@ -40,7 +54,14 @@ class StateTransition(IdentifiableElement):
|
|
40
54
|
target_snref_elem = odxrequire(et_element.find("TARGET-SNREF"))
|
41
55
|
target_snref = odxrequire(target_snref_elem.attrib["SHORT-NAME"])
|
42
56
|
|
43
|
-
|
57
|
+
external_access_method = None
|
58
|
+
if (eam_elem := et_element.find("EXTERNAL-ACCESS-METHOD")) is not None:
|
59
|
+
external_access_method = ExternalAccessMethod.from_et(eam_elem, doc_frags)
|
60
|
+
return StateTransition(
|
61
|
+
source_snref=source_snref,
|
62
|
+
target_snref=target_snref,
|
63
|
+
external_access_method=external_access_method,
|
64
|
+
**kwargs)
|
44
65
|
|
45
66
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
46
67
|
return {self.odx_id: self}
|
odxtools/structure.py
CHANGED
@@ -1,19 +1,27 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import List
|
3
|
+
from typing import List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .basicstructure import BasicStructure
|
7
7
|
from .odxlink import OdxDocFragment
|
8
|
+
from .odxtypes import odxstr_to_bool
|
8
9
|
from .utils import dataclass_fields_asdict
|
9
10
|
|
10
11
|
|
11
12
|
@dataclass
|
12
13
|
class Structure(BasicStructure):
|
14
|
+
is_visible_raw: Optional[bool]
|
13
15
|
|
14
16
|
@staticmethod
|
15
17
|
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Structure":
|
16
18
|
"""Read a STRUCTURE element from XML."""
|
17
19
|
kwargs = dataclass_fields_asdict(BasicStructure.from_et(et_element, doc_frags))
|
18
20
|
|
19
|
-
|
21
|
+
is_visible_raw = odxstr_to_bool(et_element.get("IS-VISIBLE"))
|
22
|
+
|
23
|
+
return Structure(is_visible_raw=is_visible_raw, **kwargs)
|
24
|
+
|
25
|
+
@property
|
26
|
+
def is_visible(self) -> bool:
|
27
|
+
return self.is_visible_raw in (True, None)
|
odxtools/swvariable.py
CHANGED
@@ -11,11 +11,13 @@ from .utils import dataclass_fields_asdict
|
|
11
11
|
@dataclass
|
12
12
|
class SwVariable(NamedElement):
|
13
13
|
origin: Optional[str]
|
14
|
+
oid: Optional[str]
|
14
15
|
|
15
16
|
@staticmethod
|
16
17
|
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "SwVariable":
|
17
18
|
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
|
18
19
|
|
19
20
|
origin = et_element.findtext("ORIGIN")
|
21
|
+
oid = et_element.attrib.get("OID")
|
20
22
|
|
21
|
-
return SwVariable(origin=origin, **kwargs)
|
23
|
+
return SwVariable(origin=origin, oid=oid, **kwargs)
|
odxtools/table.py
CHANGED
@@ -5,16 +5,54 @@ from xml.etree import ElementTree
|
|
5
5
|
|
6
6
|
from .admindata import AdminData
|
7
7
|
from .dataobjectproperty import DataObjectProperty
|
8
|
+
from .diagcomm import DiagComm
|
8
9
|
from .element import IdentifiableElement
|
9
|
-
from .exceptions import odxassert
|
10
|
+
from .exceptions import odxassert, odxrequire
|
10
11
|
from .nameditemlist import NamedItemList
|
11
|
-
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
12
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
12
13
|
from .snrefcontext import SnRefContext
|
13
14
|
from .specialdatagroup import SpecialDataGroup
|
14
15
|
from .tablerow import TableRow
|
15
16
|
from .utils import dataclass_fields_asdict
|
16
17
|
|
17
18
|
|
19
|
+
@dataclass
|
20
|
+
class TableDiagCommConnector:
|
21
|
+
semantic: str
|
22
|
+
|
23
|
+
diag_comm_ref: Optional[OdxLinkRef]
|
24
|
+
diag_comm_snref: Optional[str]
|
25
|
+
|
26
|
+
@property
|
27
|
+
def diag_comm(self) -> DiagComm:
|
28
|
+
return self._diag_comm
|
29
|
+
|
30
|
+
@staticmethod
|
31
|
+
def from_et(et_element: ElementTree.Element,
|
32
|
+
doc_frags: List[OdxDocFragment]) -> "TableDiagCommConnector":
|
33
|
+
|
34
|
+
semantic = odxrequire(et_element.findtext("SEMANTIC"))
|
35
|
+
diag_comm_ref = OdxLinkRef.from_et(et_element.find("DIAG-COMM-REF"), doc_frags)
|
36
|
+
diag_comm_snref = None
|
37
|
+
if (dc_snref_elem := et_element.find("DIAG-COMM-SNREF")) is not None:
|
38
|
+
diag_comm_snref = odxrequire(dc_snref_elem.get("SHORT-NAME"))
|
39
|
+
|
40
|
+
return TableDiagCommConnector(
|
41
|
+
semantic=semantic, diag_comm_ref=diag_comm_ref, diag_comm_snref=diag_comm_snref)
|
42
|
+
|
43
|
+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
44
|
+
return {}
|
45
|
+
|
46
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
47
|
+
if self.diag_comm_ref is not None:
|
48
|
+
self._diag_comm = odxlinks.resolve(self.diag_comm_ref, DiagComm)
|
49
|
+
|
50
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
51
|
+
if self.diag_comm_snref is not None:
|
52
|
+
dl = odxrequire(context.diag_layer)
|
53
|
+
self._diag_comm = resolve_snref(self.diag_comm_snref, dl.diag_comms, DiagComm)
|
54
|
+
|
55
|
+
|
18
56
|
@dataclass
|
19
57
|
class Table(IdentifiableElement):
|
20
58
|
"""This class represents a TABLE."""
|
@@ -24,7 +62,7 @@ class Table(IdentifiableElement):
|
|
24
62
|
admin_data: Optional[AdminData]
|
25
63
|
key_dop_ref: Optional[OdxLinkRef]
|
26
64
|
table_rows_raw: List[Union[TableRow, OdxLinkRef]]
|
27
|
-
|
65
|
+
table_diag_comm_connectors: List[TableDiagCommConnector]
|
28
66
|
sdgs: List[SpecialDataGroup]
|
29
67
|
|
30
68
|
@staticmethod
|
@@ -47,6 +85,10 @@ class Table(IdentifiableElement):
|
|
47
85
|
elif sub_elem.tag == "TABLE-ROW-REF":
|
48
86
|
table_rows_raw.append(OdxLinkRef.from_et(sub_elem, doc_frags))
|
49
87
|
|
88
|
+
table_diag_comm_connectors = [
|
89
|
+
TableDiagCommConnector.from_et(dcc_elem, doc_frags) for dcc_elem in et_element.iterfind(
|
90
|
+
"TABLE-DIAG-COMM-CONNECTORS/TABLE-DIAG-COMM-CONNECTOR")
|
91
|
+
]
|
50
92
|
sdgs = [
|
51
93
|
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
52
94
|
]
|
@@ -58,6 +100,7 @@ class Table(IdentifiableElement):
|
|
58
100
|
admin_data=admin_data,
|
59
101
|
key_dop_ref=key_dop_ref,
|
60
102
|
table_rows_raw=table_rows_raw,
|
103
|
+
table_diag_comm_connectors=table_diag_comm_connectors,
|
61
104
|
sdgs=sdgs,
|
62
105
|
**kwargs)
|
63
106
|
|
@@ -78,6 +121,9 @@ class Table(IdentifiableElement):
|
|
78
121
|
if isinstance(table_row_wrapper, TableRow):
|
79
122
|
result.update(table_row_wrapper._build_odxlinks())
|
80
123
|
|
124
|
+
for dcc in self.table_diag_comm_connectors:
|
125
|
+
result.update(dcc._build_odxlinks())
|
126
|
+
|
81
127
|
return result
|
82
128
|
|
83
129
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
@@ -98,7 +144,13 @@ class Table(IdentifiableElement):
|
|
98
144
|
|
99
145
|
self._table_rows = NamedItemList(table_rows)
|
100
146
|
|
147
|
+
for dcc in self.table_diag_comm_connectors:
|
148
|
+
dcc._resolve_odxlinks(odxlinks)
|
149
|
+
|
101
150
|
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
102
151
|
for table_row_wrapper in self.table_rows_raw:
|
103
152
|
if isinstance(table_row_wrapper, TableRow):
|
104
153
|
table_row_wrapper._resolve_snrefs(context)
|
154
|
+
|
155
|
+
for dcc in self.table_diag_comm_connectors:
|
156
|
+
dcc._resolve_snrefs(context)
|
odxtools/tablerow.py
CHANGED
@@ -3,15 +3,21 @@ from dataclasses import dataclass, fields
|
|
3
3
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
+
from .admindata import AdminData
|
7
|
+
from .audience import Audience
|
6
8
|
from .basicstructure import BasicStructure
|
7
9
|
from .dataobjectproperty import DataObjectProperty
|
8
10
|
from .dtcdop import DtcDop
|
9
11
|
from .element import IdentifiableElement
|
10
12
|
from .exceptions import odxassert, odxraise, odxrequire
|
13
|
+
from .functionalclass import FunctionalClass
|
14
|
+
from .nameditemlist import NamedItemList
|
11
15
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
12
|
-
from .odxtypes import AtomicOdxType
|
16
|
+
from .odxtypes import AtomicOdxType, odxstr_to_bool
|
13
17
|
from .snrefcontext import SnRefContext
|
14
18
|
from .specialdatagroup import SpecialDataGroup
|
19
|
+
from .state import State
|
20
|
+
from .statetransition import StateTransition
|
15
21
|
from .utils import dataclass_fields_asdict
|
16
22
|
|
17
23
|
if TYPE_CHECKING:
|
@@ -21,18 +27,52 @@ if TYPE_CHECKING:
|
|
21
27
|
@dataclass
|
22
28
|
class TableRow(IdentifiableElement):
|
23
29
|
"""This class represents a TABLE-ROW."""
|
24
|
-
table_ref: OdxLinkRef
|
25
30
|
key_raw: str
|
26
|
-
|
27
|
-
structure_snref: Optional[str]
|
31
|
+
table_ref: OdxLinkRef
|
28
32
|
|
29
|
-
#
|
30
|
-
#
|
33
|
+
# The spec mandates that either a structure or a non-complex DOP
|
34
|
+
# must be referenced here, i.e., exactly one of the four
|
35
|
+
# attributes below is not None
|
31
36
|
dop_ref: Optional[OdxLinkRef]
|
32
37
|
dop_snref: Optional[str]
|
38
|
+
structure_ref: Optional[OdxLinkRef]
|
39
|
+
structure_snref: Optional[str]
|
33
40
|
|
34
|
-
semantic: Optional[str]
|
35
41
|
sdgs: List[SpecialDataGroup]
|
42
|
+
audience: Optional[Audience]
|
43
|
+
functional_class_refs: List[OdxLinkRef]
|
44
|
+
state_transition_refs: List[OdxLinkRef]
|
45
|
+
pre_condition_state_refs: List[OdxLinkRef]
|
46
|
+
admin_data: Optional[AdminData]
|
47
|
+
|
48
|
+
is_executable_raw: Optional[bool]
|
49
|
+
semantic: Optional[str]
|
50
|
+
is_mandatory_raw: Optional[bool]
|
51
|
+
is_final_raw: Optional[bool]
|
52
|
+
|
53
|
+
@property
|
54
|
+
def functional_classes(self) -> NamedItemList[FunctionalClass]:
|
55
|
+
return self._functional_classes
|
56
|
+
|
57
|
+
@property
|
58
|
+
def state_transitions(self) -> NamedItemList[StateTransition]:
|
59
|
+
return self._state_transitions
|
60
|
+
|
61
|
+
@property
|
62
|
+
def pre_condition_states(self) -> NamedItemList[State]:
|
63
|
+
return self._pre_condition_states
|
64
|
+
|
65
|
+
@property
|
66
|
+
def is_executable(self) -> bool:
|
67
|
+
return self.is_executable_raw in (None, True)
|
68
|
+
|
69
|
+
@property
|
70
|
+
def is_mandatory(self) -> bool:
|
71
|
+
return self.is_mandatory_raw is True
|
72
|
+
|
73
|
+
@property
|
74
|
+
def is_final(self) -> bool:
|
75
|
+
return self.is_final_raw is True
|
36
76
|
|
37
77
|
def __post_init__(self) -> None:
|
38
78
|
self._structure: Optional[BasicStructure] = None
|
@@ -73,15 +113,49 @@ class TableRow(IdentifiableElement):
|
|
73
113
|
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
74
114
|
]
|
75
115
|
|
116
|
+
audience = None
|
117
|
+
if (audience_elem := et_element.find("AUDIENCE")) is not None:
|
118
|
+
audience = Audience.from_et(audience_elem, doc_frags)
|
119
|
+
|
120
|
+
functional_class_refs = [
|
121
|
+
odxrequire(OdxLinkRef.from_et(el, doc_frags))
|
122
|
+
for el in et_element.iterfind("FUNCT-CLASS-REFS/FUNCT-CLASS-REF")
|
123
|
+
]
|
124
|
+
|
125
|
+
state_transition_refs = [
|
126
|
+
odxrequire(OdxLinkRef.from_et(el, doc_frags))
|
127
|
+
for el in et_element.iterfind("STATE-TRANSITION-REFS/STATE-TRANSITION-REF")
|
128
|
+
]
|
129
|
+
|
130
|
+
pre_condition_state_refs = [
|
131
|
+
odxrequire(OdxLinkRef.from_et(el, doc_frags))
|
132
|
+
for el in et_element.iterfind("PRE-CONDITION-STATE-REFS/PRE-CONDITION-STATE-REF")
|
133
|
+
]
|
134
|
+
|
135
|
+
admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
|
136
|
+
|
137
|
+
is_executable_raw = odxstr_to_bool(et_element.attrib.get("IS-EXECUTABLE"))
|
138
|
+
semantic = et_element.attrib.get("SEMANTIC")
|
139
|
+
is_mandatory_raw = odxstr_to_bool(et_element.attrib.get("IS-MANDATORY"))
|
140
|
+
is_final_raw = odxstr_to_bool(et_element.attrib.get("IS-FINAL"))
|
141
|
+
|
76
142
|
return TableRow(
|
77
143
|
table_ref=table_ref,
|
78
|
-
semantic=semantic,
|
79
144
|
key_raw=key_raw,
|
80
145
|
structure_ref=structure_ref,
|
81
146
|
structure_snref=structure_snref,
|
82
147
|
dop_ref=dop_ref,
|
83
148
|
dop_snref=dop_snref,
|
84
149
|
sdgs=sdgs,
|
150
|
+
audience=audience,
|
151
|
+
functional_class_refs=functional_class_refs,
|
152
|
+
state_transition_refs=state_transition_refs,
|
153
|
+
pre_condition_state_refs=pre_condition_state_refs,
|
154
|
+
admin_data=admin_data,
|
155
|
+
is_executable_raw=is_executable_raw,
|
156
|
+
semantic=semantic,
|
157
|
+
is_mandatory_raw=is_mandatory_raw,
|
158
|
+
is_final_raw=is_final_raw,
|
85
159
|
**kwargs)
|
86
160
|
|
87
161
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
@@ -108,6 +182,15 @@ class TableRow(IdentifiableElement):
|
|
108
182
|
for sdg in self.sdgs:
|
109
183
|
sdg._resolve_odxlinks(odxlinks)
|
110
184
|
|
185
|
+
self._functional_classes = NamedItemList(
|
186
|
+
[odxlinks.resolve(fc_ref, FunctionalClass) for fc_ref in self.functional_class_refs])
|
187
|
+
|
188
|
+
self._state_transitions = NamedItemList(
|
189
|
+
[odxlinks.resolve(st_ref, StateTransition) for st_ref in self.state_transition_refs])
|
190
|
+
|
191
|
+
self._pre_condition_states = NamedItemList(
|
192
|
+
[odxlinks.resolve(pcs_ref, State) for pcs_ref in self.pre_condition_state_refs])
|
193
|
+
|
111
194
|
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
112
195
|
# convert the raw key into the proper internal
|
113
196
|
# representation. note that we cannot do this earlier because
|
@@ -12,10 +12,10 @@
|
|
12
12
|
|
13
13
|
{%- macro printDiagCodedType(dct) -%}
|
14
14
|
<DIAG-CODED-TYPE {{-make_xml_attrib("BASE-DATA-TYPE", dct.base_data_type.value)}}
|
15
|
-
{{-make_xml_attrib("BASE-TYPE-ENCODING", dct.base_type_encoding)}}
|
15
|
+
{{-make_xml_attrib("BASE-TYPE-ENCODING", dct.base_type_encoding and dct.base_type_encoding.value)}}
|
16
16
|
{{-make_bool_xml_attrib("IS-HIGHLOW-BYTE-ORDER", dct.is_highlow_byte_order_raw)}}
|
17
17
|
{%- if dct.termination is defined %}
|
18
|
-
{{-make_xml_attrib("TERMINATION", dct.termination)}}
|
18
|
+
{{-make_xml_attrib("TERMINATION", dct.termination.value)}}
|
19
19
|
{%- endif %}
|
20
20
|
{#- #} xsi:type="{{dct.dct_type}}">
|
21
21
|
{%- if dct.dct_type in ("STANDARD-LENGTH-TYPE", "LEADING-LENGTH-INFO-TYPE") %}
|
@@ -9,7 +9,11 @@
|
|
9
9
|
{%- if desc.external_docs %}
|
10
10
|
<EXTERNAL-DOCS>
|
11
11
|
{%- for ed in desc.external_docs %}
|
12
|
-
|
12
|
+
{%- if ed.description is none %}}
|
13
|
+
<EXTERNAL-DOC HREF="{{ed.href}}" />
|
14
|
+
{%- else %}}
|
15
|
+
<EXTERNAL-DOC HREF="{{ed.href}}">{{ed.description}}</EXTERNAL-DOC>
|
16
|
+
{%- endif %}}
|
13
17
|
{%- endfor %}
|
14
18
|
</EXTERNAL-DOCS>
|
15
19
|
{%- endif -%}
|
@@ -134,8 +134,8 @@
|
|
134
134
|
{{ pt.printTable(table)|indent(3) }}
|
135
135
|
{%- endfor %}
|
136
136
|
</TABLES>
|
137
|
-
{{- psd.printSpecialDataGroups(ddds.sdgs)|indent(2, first=True) }}
|
138
137
|
{%- endif %}
|
138
|
+
{{- psd.printSpecialDataGroups(ddds.sdgs)|indent(2, first=True) }}
|
139
139
|
</DIAG-DATA-DICTIONARY-SPEC>
|
140
140
|
{%- endif %}
|
141
141
|
{%- if dlr.diag_comms_raw %}
|
@@ -5,18 +5,20 @@
|
|
5
5
|
{%- import('macros/printElementId.xml.jinja2') as peid %}
|
6
6
|
{%- import('macros/printAdminData.xml.jinja2') as pad %}
|
7
7
|
{%- import('macros/printDescription.xml.jinja2') as pd %}
|
8
|
+
{%- import('macros/printSpecialData.xml.jinja2') as psd %}
|
8
9
|
|
9
10
|
{%- macro printDiagVariable(diag_var) -%}
|
10
|
-
<DIAG-VARIABLE {{-peid.printElementIdAttribs(diag_var)}}
|
11
|
+
<DIAG-VARIABLE {{-peid.printElementIdAttribs(diag_var)}}
|
12
|
+
{{-make_bool_xml_attrib("IS-READ-BEFORE-WRITE", diag_var.is_read_before_write_raw}}>
|
11
13
|
{{ peid.printElementIdSubtags(diag_variable)|indent(2) }}
|
12
14
|
{%- if diag_variable.admin_data is not none %}
|
13
15
|
{{ pad.printAdminData(diag_variable.admin_data)|indent(2) }}
|
14
16
|
{%- endif %}
|
15
17
|
<VARIABLE-GROUP-REF ID-REF="{{ diag_var.ref_id }}" />
|
16
18
|
{%- if diag_variable.sw_variables %}
|
17
|
-
|
19
|
+
<SW-VARIABLES>
|
18
20
|
{%- for sw_var in diag_variable.sw_variables %}
|
19
|
-
<SW-VARIABLE {{-peid.printElementIdAttribs(sw_var)}}>
|
21
|
+
<SW-VARIABLE {{-peid.printElementIdAttribs(sw_var)}} {{- make_xml_attrib("OID", sw_var.oid) }}>
|
20
22
|
{{ peid.printElementIdSubtags(sw_var)|indent(6) }}
|
21
23
|
{%- if sw_var.origin is not none %}
|
22
24
|
<ORIGIN>{{ sw_var.origin }}</ORIGIN>
|
@@ -56,6 +58,13 @@
|
|
56
58
|
{%- endfor %}
|
57
59
|
</COMM-RELATIONS>
|
58
60
|
{%- endif %}
|
61
|
+
{%- if diag_variable.table_snref is not none %}
|
62
|
+
<SNREF-TO-TABLE-ROW>
|
63
|
+
<TABLE-SNREF SHORT-NAME="{{diag_variable.table_snref}}" />
|
64
|
+
<TABLE-ROW-SNREF SHORT-NAME="{{diag_variable.table_row_snref}}" />
|
65
|
+
</SNREF-TO-TABLE-ROW>
|
66
|
+
{%- endif %}
|
67
|
+
{{- psd.printSpecialDataGroups(ddds.sdgs)|indent(2, first=True) }}
|
59
68
|
</DIAG-VARIABLE>
|
60
69
|
{%- endmacro -%}
|
61
70
|
|
@@ -5,9 +5,13 @@
|
|
5
5
|
-#}
|
6
6
|
|
7
7
|
{%- import('macros/printElementId.xml.jinja2') as peid %}
|
8
|
+
{%- import('macros/printAdminData.xml.jinja2') as pad %}
|
8
9
|
|
9
10
|
{%- macro printFunctionalClass(fc) -%}
|
10
11
|
<FUNCT-CLASS {{-peid.printElementIdAttribs(fc)}}>
|
11
12
|
{{ peid.printElementIdSubtags(fc)|indent(1) }}
|
13
|
+
{%- if fc.admin_data is not none -%}
|
14
|
+
{{ pad.printAdminData(fc.admin_data)|indent(1) }}
|
15
|
+
{%- endif -%}
|
12
16
|
</FUNCT-CLASS>
|
13
17
|
{%- endmacro -%}
|
@@ -17,6 +17,15 @@
|
|
17
17
|
{%- endfor %}
|
18
18
|
</NOT-INHERITED-DIAG-COMMS>
|
19
19
|
{%- endif %}
|
20
|
+
{%- if par.not_inherited_variables %}
|
21
|
+
<NOT-INHERITED-VARIABLES>
|
22
|
+
{%- for nivar in par.not_inherited_variables %}
|
23
|
+
<NOT-INHERITED-VARIABLE>
|
24
|
+
<DIAG-VARIABLE-SNREF SHORT-NAME="{{nivar}}"/>
|
25
|
+
</NOT-INHERITED-VARIABLE>
|
26
|
+
{%- endfor %}
|
27
|
+
</NOT-INHERITED-VARIABLES>
|
28
|
+
{%- endif %}
|
20
29
|
{%- if par.not_inherited_dops %}
|
21
30
|
<NOT-INHERITED-DOPS>
|
22
31
|
{%- for nidop in par.not_inherited_dops %}
|
@@ -26,6 +35,24 @@
|
|
26
35
|
{%- endfor %}
|
27
36
|
</NOT-INHERITED-DOPS>
|
28
37
|
{%- endif %}
|
38
|
+
{%- if par.not_inherited_tables %}
|
39
|
+
<NOT-INHERITED-TABLES>
|
40
|
+
{%- for nitable in par.not_inherited_tables %}
|
41
|
+
<NOT-INHERITED-TABLE>
|
42
|
+
<TABLE-SNREF SHORT-NAME="{{nitable}}"/>
|
43
|
+
</NOT-INHERITED-TABLE>
|
44
|
+
{%- endfor %}
|
45
|
+
</NOT-INHERITED-TABLES>
|
46
|
+
{%- endif %}
|
47
|
+
{%- if par.not_inherited_global_neg_responses %}
|
48
|
+
<NOT-INHERITED-GLOBAL-NEG-RESPONSES>
|
49
|
+
{%- for nignr in par.not_inherited_global_neg_responses %}
|
50
|
+
<NOT-INHERITED-GLOBAL-NEG-RESPONSE>
|
51
|
+
<GLOBAL-NEG-RESPONSE-SNREF SHORT-NAME="{{nignr}}"/>
|
52
|
+
</NOT-INHERITED-GLOBAL-NEG-RESPONSE>
|
53
|
+
{%- endfor %}
|
54
|
+
</NOT-INHERITED-GLOBAL-NEG-RESPONSES>
|
55
|
+
{%- endif %}
|
29
56
|
</PARENT-REF>
|
30
57
|
{%- endmacro -%}
|
31
58
|
|
@@ -13,7 +13,7 @@
|
|
13
13
|
{%- set dlr = protocol.protocol_raw %}
|
14
14
|
|
15
15
|
{%- set cps_docfrag = dlr.comparam_spec_ref.ref_docs[-1] %}
|
16
|
-
<COMPARAM-SPEC-REF ID-REF="{{dlr.comparam_spec_ref.ref_id}}" DOCREF="{{cps_docfrag.doc_name}}" DOCTYPE="{{cps_docfrag.doc_type}}" />
|
16
|
+
<COMPARAM-SPEC-REF ID-REF="{{dlr.comparam_spec_ref.ref_id}}" DOCREF="{{cps_docfrag.doc_name}}" DOCTYPE="{{cps_docfrag.doc_type.value}}" />
|
17
17
|
|
18
18
|
{%- if dlr.prot_stack_snref is not none %}
|
19
19
|
<PROT-STACK-SNREF SHORT-NAME="{{ dlr.prot_stack_snref }}" />
|