odxtools 6.6.1__py3-none-any.whl → 6.7.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/__init__.py +5 -5
- odxtools/basicstructure.py +7 -8
- odxtools/cli/_parser_utils.py +15 -0
- odxtools/cli/_print_utils.py +4 -3
- odxtools/cli/browse.py +19 -14
- odxtools/cli/compare.py +24 -16
- odxtools/cli/decode.py +2 -1
- odxtools/cli/dummy_sub_parser.py +3 -1
- odxtools/cli/find.py +2 -1
- odxtools/cli/list.py +2 -1
- odxtools/cli/main.py +1 -0
- odxtools/cli/snoop.py +4 -1
- odxtools/comparaminstance.py +7 -5
- odxtools/compumethods/compumethod.py +2 -4
- odxtools/compumethods/compuscale.py +45 -5
- odxtools/compumethods/createanycompumethod.py +28 -36
- odxtools/compumethods/limit.py +70 -36
- odxtools/compumethods/linearcompumethod.py +68 -59
- odxtools/compumethods/tabintpcompumethod.py +19 -8
- odxtools/compumethods/texttablecompumethod.py +32 -36
- odxtools/dataobjectproperty.py +13 -10
- odxtools/decodestate.py +6 -3
- odxtools/determinenumberofitems.py +1 -1
- odxtools/diagcodedtype.py +5 -4
- odxtools/diagdatadictionaryspec.py +108 -83
- odxtools/diaglayer.py +75 -35
- odxtools/diaglayertype.py +17 -5
- odxtools/diagservice.py +1 -1
- odxtools/dopbase.py +4 -2
- odxtools/dtcdop.py +7 -5
- odxtools/dynamiclengthfield.py +6 -5
- odxtools/endofpdufield.py +4 -4
- odxtools/environmentdatadescription.py +4 -2
- odxtools/inputparam.py +1 -1
- odxtools/internalconstr.py +14 -5
- odxtools/isotp_state_machine.py +14 -6
- odxtools/message.py +1 -1
- odxtools/multiplexer.py +18 -13
- odxtools/multiplexercase.py +27 -5
- odxtools/multiplexerswitchkey.py +1 -1
- odxtools/nameditemlist.py +7 -6
- odxtools/odxlink.py +2 -2
- odxtools/odxtypes.py +56 -3
- odxtools/outputparam.py +2 -2
- odxtools/parameterinfo.py +12 -5
- odxtools/parameters/codedconstparameter.py +33 -12
- odxtools/parameters/createanyparameter.py +19 -193
- odxtools/parameters/dynamicparameter.py +21 -1
- odxtools/parameters/lengthkeyparameter.py +28 -4
- odxtools/parameters/matchingrequestparameter.py +27 -9
- odxtools/parameters/nrcconstparameter.py +34 -11
- odxtools/parameters/parameter.py +58 -32
- odxtools/parameters/parameterwithdop.py +28 -15
- odxtools/parameters/physicalconstantparameter.py +28 -4
- odxtools/parameters/reservedparameter.py +32 -18
- odxtools/parameters/systemparameter.py +25 -2
- odxtools/parameters/tableentryparameter.py +45 -6
- odxtools/parameters/tablekeyparameter.py +43 -10
- odxtools/parameters/tablestructparameter.py +36 -14
- odxtools/parameters/valueparameter.py +24 -2
- odxtools/paramlengthinfotype.py +4 -1
- odxtools/parentref.py +4 -1
- odxtools/scaleconstr.py +11 -5
- odxtools/statetransition.py +1 -1
- odxtools/staticfield.py +101 -0
- odxtools/table.py +2 -1
- odxtools/tablerow.py +11 -4
- odxtools/templates/macros/printDOP.xml.jinja2 +30 -34
- odxtools/templates/macros/printMux.xml.jinja2 +3 -2
- odxtools/templates/macros/printParam.xml.jinja2 +9 -9
- odxtools/templates/macros/printStaticField.xml.jinja2 +15 -0
- odxtools/templates/macros/printVariant.xml.jinja2 +8 -0
- odxtools/uds.py +2 -2
- odxtools/version.py +2 -2
- odxtools/write_pdx_file.py +3 -3
- {odxtools-6.6.1.dist-info → odxtools-6.7.1.dist-info}/METADATA +28 -16
- {odxtools-6.6.1.dist-info → odxtools-6.7.1.dist-info}/RECORD +81 -79
- {odxtools-6.6.1.dist-info → odxtools-6.7.1.dist-info}/WHEEL +1 -1
- {odxtools-6.6.1.dist-info → odxtools-6.7.1.dist-info}/LICENSE +0 -0
- {odxtools-6.6.1.dist-info → odxtools-6.7.1.dist-info}/entry_points.txt +0 -0
- {odxtools-6.6.1.dist-info → odxtools-6.7.1.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,17 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
import warnings
|
3
3
|
from dataclasses import dataclass
|
4
|
-
from typing import TYPE_CHECKING, Any, Dict, Optional, cast
|
4
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast
|
5
|
+
from xml.etree import ElementTree
|
6
|
+
|
7
|
+
from typing_extensions import override
|
5
8
|
|
6
9
|
from ..decodestate import DecodeState
|
7
10
|
from ..encodestate import EncodeState
|
8
|
-
from ..exceptions import EncodeError, OdxWarning, odxraise
|
9
|
-
from ..odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
11
|
+
from ..exceptions import DecodeError, EncodeError, OdxWarning, odxraise, odxrequire
|
12
|
+
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
10
13
|
from ..odxtypes import ParameterValue
|
14
|
+
from ..utils import dataclass_fields_asdict
|
11
15
|
from .parameter import Parameter, ParameterType
|
12
16
|
from .tablekeyparameter import TableKeyParameter
|
13
17
|
|
@@ -21,23 +25,42 @@ class TableStructParameter(Parameter):
|
|
21
25
|
table_key_ref: Optional[OdxLinkRef]
|
22
26
|
table_key_snref: Optional[str]
|
23
27
|
|
28
|
+
@staticmethod
|
29
|
+
@override
|
30
|
+
def from_et(et_element: ElementTree.Element,
|
31
|
+
doc_frags: List[OdxDocFragment]) -> "TableStructParameter":
|
32
|
+
|
33
|
+
kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
|
34
|
+
|
35
|
+
table_key_ref = OdxLinkRef.from_et(et_element.find("TABLE-KEY-REF"), doc_frags)
|
36
|
+
table_key_snref = None
|
37
|
+
if (table_key_snref_elem := et_element.find("TABLE-KEY-SNREF")) is not None:
|
38
|
+
table_key_snref = odxrequire(table_key_snref_elem.get("SHORT-NAME"))
|
39
|
+
|
40
|
+
return TableStructParameter(
|
41
|
+
table_key_ref=table_key_ref, table_key_snref=table_key_snref, **kwargs)
|
42
|
+
|
24
43
|
def __post_init__(self) -> None:
|
25
44
|
if self.table_key_ref is None and self.table_key_snref is None:
|
26
45
|
odxraise("Either table_key_ref or table_key_snref must be defined.")
|
27
46
|
|
28
47
|
@property
|
48
|
+
@override
|
29
49
|
def parameter_type(self) -> ParameterType:
|
30
50
|
return "TABLE-STRUCT"
|
31
51
|
|
52
|
+
@override
|
32
53
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
33
54
|
return super()._build_odxlinks()
|
34
55
|
|
56
|
+
@override
|
35
57
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
36
58
|
super()._resolve_odxlinks(odxlinks)
|
37
59
|
|
38
60
|
if self.table_key_ref is not None:
|
39
|
-
self._table_key = odxlinks.resolve(self.table_key_ref)
|
61
|
+
self._table_key = odxlinks.resolve(self.table_key_ref, TableKeyParameter)
|
40
62
|
|
63
|
+
@override
|
41
64
|
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
42
65
|
super()._resolve_snrefs(diag_layer)
|
43
66
|
|
@@ -53,13 +76,16 @@ class TableStructParameter(Parameter):
|
|
53
76
|
return self._table_key
|
54
77
|
|
55
78
|
@property
|
79
|
+
@override
|
56
80
|
def is_required(self) -> bool:
|
57
81
|
return True
|
58
82
|
|
59
83
|
@property
|
84
|
+
@override
|
60
85
|
def is_settable(self) -> bool:
|
61
86
|
return True
|
62
87
|
|
88
|
+
@override
|
63
89
|
def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
|
64
90
|
physical_value = encode_state.parameter_values.get(self.short_name)
|
65
91
|
|
@@ -122,22 +148,21 @@ class TableStructParameter(Parameter):
|
|
122
148
|
return tr.dop.convert_physical_to_bytes(
|
123
149
|
tr_value, encode_state=encode_state, bit_position=bit_position)
|
124
150
|
|
151
|
+
@override
|
125
152
|
def encode_into_pdu(self, encode_state: EncodeState) -> bytes:
|
126
153
|
return super().encode_into_pdu(encode_state)
|
127
154
|
|
128
|
-
|
129
|
-
|
130
|
-
if self.byte_position is not None:
|
131
|
-
decode_state.cursor_byte_position = decode_state.origin_byte_position + self.byte_position
|
132
|
-
|
155
|
+
@override
|
156
|
+
def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
133
157
|
# find the selected table row
|
134
158
|
key_name = self.table_key.short_name
|
135
159
|
|
136
160
|
decode_state.table_keys[key_name]
|
137
161
|
table_row = decode_state.table_keys.get(key_name)
|
138
162
|
if table_row is None:
|
139
|
-
|
140
|
-
|
163
|
+
odxraise(
|
164
|
+
f"No table key '{key_name}' found when decoding "
|
165
|
+
f"table struct parameter '{str(self.short_name)}'", DecodeError)
|
141
166
|
dummy_val = cast(str, None), cast(int, None)
|
142
167
|
return dummy_val
|
143
168
|
|
@@ -145,14 +170,11 @@ class TableStructParameter(Parameter):
|
|
145
170
|
if table_row.dop is not None:
|
146
171
|
dop = table_row.dop
|
147
172
|
val = dop.decode_from_pdu(decode_state)
|
148
|
-
decode_state.cursor_byte_position = max(decode_state.cursor_byte_position, orig_cursor)
|
149
173
|
return (table_row.short_name, val)
|
150
174
|
elif table_row.structure is not None:
|
151
175
|
val = table_row.structure.decode_from_pdu(decode_state)
|
152
|
-
decode_state.cursor_byte_position = max(decode_state.cursor_byte_position, orig_cursor)
|
153
176
|
return (table_row.short_name, val)
|
154
177
|
else:
|
155
178
|
# the table row associated with the key neither defines a
|
156
179
|
# DOP nor a structure -> ignore it
|
157
|
-
decode_state.cursor_byte_position = max(decode_state.cursor_byte_position, orig_cursor)
|
158
180
|
return (table_row.short_name, cast(int, None))
|
@@ -1,12 +1,16 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import TYPE_CHECKING, Any, Dict, Optional
|
3
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from typing_extensions import override
|
4
7
|
|
5
8
|
from ..dataobjectproperty import DataObjectProperty
|
6
9
|
from ..encodestate import EncodeState
|
7
10
|
from ..exceptions import odxraise, odxrequire
|
8
|
-
from ..odxlink import OdxLinkDatabase, OdxLinkId
|
11
|
+
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
9
12
|
from ..odxtypes import AtomicOdxType
|
13
|
+
from ..utils import dataclass_fields_asdict
|
10
14
|
from .parameter import ParameterType
|
11
15
|
from .parameterwithdop import ParameterWithDOP
|
12
16
|
|
@@ -21,16 +25,31 @@ class ValueParameter(ParameterWithDOP):
|
|
21
25
|
def __post_init__(self) -> None:
|
22
26
|
self._physical_default_value: Optional[AtomicOdxType] = None
|
23
27
|
|
28
|
+
@staticmethod
|
29
|
+
@override
|
30
|
+
def from_et(et_element: ElementTree.Element,
|
31
|
+
doc_frags: List[OdxDocFragment]) -> "ValueParameter":
|
32
|
+
|
33
|
+
kwargs = dataclass_fields_asdict(ParameterWithDOP.from_et(et_element, doc_frags))
|
34
|
+
|
35
|
+
physical_default_value_raw = et_element.findtext("PHYSICAL-DEFAULT-VALUE")
|
36
|
+
|
37
|
+
return ValueParameter(physical_default_value_raw=physical_default_value_raw, **kwargs)
|
38
|
+
|
24
39
|
@property
|
40
|
+
@override
|
25
41
|
def parameter_type(self) -> ParameterType:
|
26
42
|
return "VALUE"
|
27
43
|
|
44
|
+
@override
|
28
45
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
29
46
|
return super()._build_odxlinks()
|
30
47
|
|
48
|
+
@override
|
31
49
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
32
50
|
super()._resolve_odxlinks(odxlinks)
|
33
51
|
|
52
|
+
@override
|
34
53
|
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
35
54
|
super()._resolve_snrefs(diag_layer)
|
36
55
|
|
@@ -48,13 +67,16 @@ class ValueParameter(ParameterWithDOP):
|
|
48
67
|
return self._physical_default_value
|
49
68
|
|
50
69
|
@property
|
70
|
+
@override
|
51
71
|
def is_required(self) -> bool:
|
52
72
|
return self._physical_default_value is None
|
53
73
|
|
54
74
|
@property
|
75
|
+
@override
|
55
76
|
def is_settable(self) -> bool:
|
56
77
|
return True
|
57
78
|
|
79
|
+
@override
|
58
80
|
def get_coded_value_as_bytes(self, encode_state: EncodeState) -> bytes:
|
59
81
|
physical_value = encode_state.parameter_values.get(self.short_name,
|
60
82
|
self.physical_default_value)
|
odxtools/paramlengthinfotype.py
CHANGED
@@ -30,7 +30,10 @@ class ParamLengthInfoType(DiagCodedType):
|
|
30
30
|
"""Recursively resolve any odxlinks references"""
|
31
31
|
super()._resolve_odxlinks(odxlinks)
|
32
32
|
|
33
|
-
|
33
|
+
if TYPE_CHECKING:
|
34
|
+
self._length_key = odxlinks.resolve(self.length_key_ref, LengthKeyParameter)
|
35
|
+
else:
|
36
|
+
self._length_key = odxlinks.resolve(self.length_key_ref)
|
34
37
|
|
35
38
|
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
36
39
|
"""Recursively resolve any short-name references"""
|
odxtools/parentref.py
CHANGED
@@ -71,7 +71,10 @@ class ParentRef:
|
|
71
71
|
return {}
|
72
72
|
|
73
73
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
74
|
-
|
74
|
+
if TYPE_CHECKING:
|
75
|
+
self._layer = odxlinks.resolve(self.layer_ref, DiagLayer)
|
76
|
+
else:
|
77
|
+
self._layer = odxlinks.resolve(self.layer_ref)
|
75
78
|
|
76
79
|
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
77
80
|
pass
|
odxtools/scaleconstr.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from enum import Enum
|
4
|
-
from typing import Optional
|
4
|
+
from typing import List, Optional
|
5
5
|
from xml.etree import ElementTree
|
6
6
|
|
7
7
|
from .compumethods.limit import Limit
|
8
8
|
from .exceptions import odxraise, odxrequire
|
9
|
+
from .odxlink import OdxDocFragment
|
9
10
|
from .odxtypes import DataType
|
10
11
|
from .utils import create_description_from_et
|
11
12
|
|
@@ -27,14 +28,18 @@ class ScaleConstr:
|
|
27
28
|
lower_limit: Optional[Limit]
|
28
29
|
upper_limit: Optional[Limit]
|
29
30
|
validity: ValidType
|
31
|
+
value_type: DataType
|
30
32
|
|
31
33
|
@staticmethod
|
32
|
-
def
|
34
|
+
def scale_constr_from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment], *,
|
35
|
+
value_type: DataType) -> "ScaleConstr":
|
33
36
|
short_label = et_element.findtext("SHORT-LABEL")
|
34
37
|
description = create_description_from_et(et_element.find("DESC"))
|
35
38
|
|
36
|
-
lower_limit = Limit.
|
37
|
-
|
39
|
+
lower_limit = Limit.limit_from_et(
|
40
|
+
et_element.find("LOWER-LIMIT"), doc_frags, value_type=value_type)
|
41
|
+
upper_limit = Limit.limit_from_et(
|
42
|
+
et_element.find("UPPER-LIMIT"), doc_frags, value_type=value_type)
|
38
43
|
|
39
44
|
validity_str = odxrequire(et_element.get("VALIDITY"))
|
40
45
|
try:
|
@@ -47,4 +52,5 @@ class ScaleConstr:
|
|
47
52
|
description=description,
|
48
53
|
lower_limit=lower_limit,
|
49
54
|
upper_limit=upper_limit,
|
50
|
-
validity=validity
|
55
|
+
validity=validity,
|
56
|
+
value_type=value_type)
|
odxtools/statetransition.py
CHANGED
@@ -20,7 +20,7 @@ class StateTransition(IdentifiableElement):
|
|
20
20
|
"""
|
21
21
|
source_snref: str
|
22
22
|
target_snref: str
|
23
|
-
#external_access_method: Optional[ExternalAccessMethod] # TODO
|
23
|
+
# external_access_method: Optional[ExternalAccessMethod] # TODO
|
24
24
|
|
25
25
|
@property
|
26
26
|
def source_state(self) -> State:
|
odxtools/staticfield.py
ADDED
@@ -0,0 +1,101 @@
|
|
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 typing_extensions import override
|
7
|
+
|
8
|
+
from .decodestate import DecodeState
|
9
|
+
from .encodestate import EncodeState
|
10
|
+
from .exceptions import odxassert, odxraise, odxrequire
|
11
|
+
from .field import Field
|
12
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
13
|
+
from .odxtypes import ParameterValue
|
14
|
+
from .utils import dataclass_fields_asdict
|
15
|
+
|
16
|
+
if TYPE_CHECKING:
|
17
|
+
from .diaglayer import DiagLayer
|
18
|
+
|
19
|
+
|
20
|
+
@dataclass
|
21
|
+
class StaticField(Field):
|
22
|
+
"""Array of a fixed number of structure objects"""
|
23
|
+
fixed_number_of_items: int
|
24
|
+
item_byte_size: int
|
25
|
+
|
26
|
+
@staticmethod
|
27
|
+
@override
|
28
|
+
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "StaticField":
|
29
|
+
kwargs = dataclass_fields_asdict(Field.from_et(et_element, doc_frags))
|
30
|
+
|
31
|
+
fixed_number_of_items = int(odxrequire(et_element.findtext('FIXED-NUMBER-OF-ITEMS')))
|
32
|
+
item_byte_size = int(odxrequire(et_element.findtext('ITEM-BYTE-SIZE')))
|
33
|
+
|
34
|
+
return StaticField(
|
35
|
+
fixed_number_of_items=fixed_number_of_items, item_byte_size=item_byte_size, **kwargs)
|
36
|
+
|
37
|
+
@override
|
38
|
+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
39
|
+
odxlinks = super()._build_odxlinks()
|
40
|
+
return odxlinks
|
41
|
+
|
42
|
+
@override
|
43
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
44
|
+
super()._resolve_odxlinks(odxlinks)
|
45
|
+
|
46
|
+
@override
|
47
|
+
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
48
|
+
super()._resolve_snrefs(diag_layer)
|
49
|
+
|
50
|
+
@override
|
51
|
+
def convert_physical_to_bytes(
|
52
|
+
self,
|
53
|
+
physical_value: ParameterValue,
|
54
|
+
encode_state: EncodeState,
|
55
|
+
bit_position: int = 0,
|
56
|
+
) -> bytes:
|
57
|
+
if not isinstance(physical_value,
|
58
|
+
(tuple, list)) or len(physical_value) != self.fixed_number_of_items:
|
59
|
+
odxraise(f"Value for static field '{self.short_name}' "
|
60
|
+
f"must be a list of size {self.fixed_number_of_items}")
|
61
|
+
|
62
|
+
result = bytearray()
|
63
|
+
for val in physical_value:
|
64
|
+
if not isinstance(val, dict):
|
65
|
+
odxraise(f"The individual parameter values for static field '{self.short_name}' "
|
66
|
+
f"must be dictionaries for structure '{self.structure.short_name}'")
|
67
|
+
|
68
|
+
data = self.structure.convert_physical_to_bytes(val, encode_state)
|
69
|
+
|
70
|
+
if len(data) > self.item_byte_size:
|
71
|
+
odxraise(f"Insufficient item byte size for static field {self.short_name}: "
|
72
|
+
f"Is {self.item_byte_size} bytes, but need at least {len(data)} bytes")
|
73
|
+
data = data[:self.item_byte_size]
|
74
|
+
elif len(data) < self.item_byte_size:
|
75
|
+
# add some padding bytes
|
76
|
+
data = data.ljust(self.item_byte_size, b'\x00')
|
77
|
+
|
78
|
+
result += data
|
79
|
+
|
80
|
+
return result
|
81
|
+
|
82
|
+
@override
|
83
|
+
def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
84
|
+
|
85
|
+
odxassert(decode_state.cursor_bit_position == 0,
|
86
|
+
"No bit position can be specified for static length fields!")
|
87
|
+
|
88
|
+
result: List[ParameterValue] = []
|
89
|
+
for _ in range(self.fixed_number_of_items):
|
90
|
+
orig_cursor = decode_state.cursor_byte_position
|
91
|
+
|
92
|
+
if decode_state.cursor_byte_position - orig_cursor > self.item_byte_size:
|
93
|
+
odxraise(f"Insufficient item byte size for static field {self.short_name}: "
|
94
|
+
f"Is {self.item_byte_size} bytes, but need at least "
|
95
|
+
f"{decode_state.cursor_byte_position - orig_cursor} bytes")
|
96
|
+
|
97
|
+
result.append(self.structure.decode_from_pdu(decode_state))
|
98
|
+
|
99
|
+
decode_state.cursor_byte_position = orig_cursor + self.item_byte_size
|
100
|
+
|
101
|
+
return result
|
odxtools/table.py
CHANGED
@@ -45,7 +45,8 @@ class Table(IdentifiableElement):
|
|
45
45
|
for sub_elem in et_element:
|
46
46
|
if sub_elem.tag == "TABLE-ROW":
|
47
47
|
table_rows_raw.append(
|
48
|
-
TableRow.
|
48
|
+
TableRow.tablerow_from_et(
|
49
|
+
sub_elem, doc_frags, table_ref=OdxLinkRef.from_id(odx_id)))
|
49
50
|
elif sub_elem.tag == "TABLE-ROW-REF":
|
50
51
|
table_rows_raw.append(OdxLinkRef.from_et(sub_elem, doc_frags))
|
51
52
|
|
odxtools/tablerow.py
CHANGED
@@ -51,9 +51,13 @@ class TableRow(IdentifiableElement):
|
|
51
51
|
)
|
52
52
|
|
53
53
|
@staticmethod
|
54
|
-
def from_et(
|
55
|
-
|
56
|
-
|
54
|
+
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> Any:
|
55
|
+
raise RuntimeError(
|
56
|
+
"Calling TableRow.from_et() is not allowed. Use TableRow.tablerow_from_et().")
|
57
|
+
|
58
|
+
@staticmethod
|
59
|
+
def tablerow_from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment], *,
|
60
|
+
table_ref: OdxLinkRef) -> "TableRow":
|
57
61
|
"""Reads a TABLE-ROW."""
|
58
62
|
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
59
63
|
semantic = et_element.get("SEMANTIC")
|
@@ -95,7 +99,10 @@ class TableRow(IdentifiableElement):
|
|
95
99
|
if not isinstance(self._dop, (DataObjectProperty, DtcDop)):
|
96
100
|
odxraise("The DOP-REF of TABLE-ROWs must reference a simple DOP!")
|
97
101
|
|
98
|
-
|
102
|
+
if TYPE_CHECKING:
|
103
|
+
self._table = odxlinks.resolve(self.table_ref, Table)
|
104
|
+
else:
|
105
|
+
self._table = odxlinks.resolve(self.table_ref)
|
99
106
|
|
100
107
|
for sdg in self.sdgs:
|
101
108
|
sdg._resolve_odxlinks(odxlinks)
|
@@ -43,12 +43,24 @@
|
|
43
43
|
{%- endif %}
|
44
44
|
{%- endmacro -%}
|
45
45
|
|
46
|
-
{%- macro
|
47
|
-
{%- if
|
48
|
-
{
|
49
|
-
{
|
50
|
-
{
|
51
|
-
{
|
46
|
+
{%- macro printLimit(tag_name, limit_obj) -%}
|
47
|
+
{%- if limit_obj is not none %}
|
48
|
+
<{{tag_name}}
|
49
|
+
{%- if limit_obj.interval_type is not none %}
|
50
|
+
{{- make_xml_attrib("INTERVAL-TYPE", limit_obj.interval_type.value) }}
|
51
|
+
{%- endif %}
|
52
|
+
{%- if limit_obj.value_raw is none %}
|
53
|
+
{#- #}/>
|
54
|
+
{%- else %}
|
55
|
+
{#- #}>
|
56
|
+
{%- if hasattr(limit_obj._value, 'hex') -%}
|
57
|
+
{#- bytes or bytarray limit #}
|
58
|
+
{{- limit_obj._value.hex().upper() }}
|
59
|
+
{%- else -%}
|
60
|
+
{{- limit_obj._value }}
|
61
|
+
{%- endif -%}
|
62
|
+
</{{tag_name}}>
|
63
|
+
{%- endif -%}
|
52
64
|
{%- endif -%}
|
53
65
|
{%- endmacro -%}
|
54
66
|
|
@@ -62,8 +74,8 @@
|
|
62
74
|
{{sc.description}}
|
63
75
|
</DESC>
|
64
76
|
{%- endif %}
|
65
|
-
|
66
|
-
|
77
|
+
{{printLimit("LOWER-LIMIT", sc.lower_limit) }}
|
78
|
+
{{printLimit("UPPER-LIMIT", sc.upper_limit) }}
|
67
79
|
</SCALE-CONSTR>
|
68
80
|
{%- endmacro -%}
|
69
81
|
|
@@ -73,12 +85,8 @@
|
|
73
85
|
{%- else %}
|
74
86
|
<INTERNAL-CONSTR>
|
75
87
|
{%- endif %}
|
76
|
-
{
|
77
|
-
|
78
|
-
{%- endif %}
|
79
|
-
{%- if ic.upper_limit %}
|
80
|
-
<UPPER-LIMIT>{{printLimitValue(ic.upper_limit.value)}}</UPPER-LIMIT>
|
81
|
-
{%- endif %}
|
88
|
+
{{printLimit("LOWER-LIMIT", ic.lower_limit) }}
|
89
|
+
{{printLimit("UPPER-LIMIT", ic.upper_limit) }}
|
82
90
|
{%- if ic.scale_constrs %}
|
83
91
|
<SCALE-CONSTRS>
|
84
92
|
{%- for sc in ic.scale_constrs %}
|
@@ -109,12 +117,8 @@
|
|
109
117
|
{{cs.description}}
|
110
118
|
</DESC>
|
111
119
|
{%- endif %}
|
112
|
-
{
|
113
|
-
|
114
|
-
{%- endif %}
|
115
|
-
{%- if cs.upper_limit is not none %}
|
116
|
-
<UPPER-LIMIT>{{printLimitValue(cs.upper_limit.value)}}</UPPER-LIMIT>
|
117
|
-
{%- endif %}
|
120
|
+
{{printLimit("LOWER-LIMIT", cs.lower_limit) }}
|
121
|
+
{{printLimit("UPPER-LIMIT", cs.upper_limit) }}
|
118
122
|
{%- if cs.compu_inverse_value is not none %}
|
119
123
|
<COMPU-INVERSE-VALUE>
|
120
124
|
<V>{{cs.compu_inverse_value}}</V>
|
@@ -141,12 +145,8 @@
|
|
141
145
|
<COMPU-INTERNAL-TO-PHYS>
|
142
146
|
<COMPU-SCALES>
|
143
147
|
<COMPU-SCALE>
|
144
|
-
|
145
|
-
|
146
|
-
{%- endif %}
|
147
|
-
{%- if cm.internal_upper_limit is not none and cm.internal_upper_limit.interval_type.value != "INFINITE" %}
|
148
|
-
<UPPER-LIMIT>{{printLimitValue(cm.internal_upper_limit.value)}}</UPPER-LIMIT>
|
149
|
-
{%- endif %}
|
148
|
+
{{printLimit("LOWER-LIMIT", cm.internal_lower_limit) }}
|
149
|
+
{{printLimit("UPPER-LIMIT", cm.internal_upper_limit) }}
|
150
150
|
<COMPU-RATIONAL-COEFFS>
|
151
151
|
<COMPU-NUMERATOR>
|
152
152
|
<V>{{cm.offset}}</V>
|
@@ -166,12 +166,8 @@
|
|
166
166
|
<COMPU-SCALES>
|
167
167
|
{%- for lm in cm.linear_methods %}
|
168
168
|
<COMPU-SCALE>
|
169
|
-
|
170
|
-
|
171
|
-
{%- endif %}
|
172
|
-
{%- if lm.internal_upper_limit is not none and lm.internal_upper_limit.interval_type.value != "INFINITE" %}
|
173
|
-
<UPPER-LIMIT>{{printLimitValue(lm.internal_upper_limit.value)}}</UPPER-LIMIT>
|
174
|
-
{%- endif %}
|
169
|
+
{{printLimit("LOWER-LIMIT", lm.internal_lower_limit) }}
|
170
|
+
{{printLimit("UPPER-LIMIT", lm.internal_upper_limit) }}
|
175
171
|
<COMPU-RATIONAL-COEFFS>
|
176
172
|
<COMPU-NUMERATOR>
|
177
173
|
<V>{{lm.offset}}</V>
|
@@ -191,8 +187,8 @@
|
|
191
187
|
<COMPU-INTERNAL-TO-PHYS>
|
192
188
|
<COMPU-SCALES>
|
193
189
|
{%- for idx in range( cm.internal_points | length ) %}
|
194
|
-
|
195
|
-
<LOWER-LIMIT
|
190
|
+
<COMPU-SCALE>
|
191
|
+
<LOWER-LIMIT>{{ cm.internal_points[idx] }}</LOWER-LIMIT>
|
196
192
|
<COMPU-CONST>
|
197
193
|
<V>{{ cm.physical_points[idx] }}</V>
|
198
194
|
</COMPU-CONST>
|
@@ -4,6 +4,7 @@
|
|
4
4
|
-#}
|
5
5
|
|
6
6
|
{%- import('macros/printElementId.xml.jinja2') as peid %}
|
7
|
+
{%- import('macros/printDOP.xml.jinja2') as pdop %}
|
7
8
|
|
8
9
|
{%- macro printMux(mux) %}
|
9
10
|
<MUX ID="{{mux.odx_id.local_id}}"
|
@@ -40,8 +41,8 @@
|
|
40
41
|
{%- if case.structure_snref is not none %}
|
41
42
|
<STRUCTURE-SNREF SHORT_NAME="{{case.structure_snref}}"/>
|
42
43
|
{%- endif %}
|
43
|
-
|
44
|
-
|
44
|
+
{{ pdop.printLimit("LOWER-LIMIT", case.lower_limit) }}
|
45
|
+
{{ pdop.printLimit("UPPER-LIMIT", case.upper_limit) }}
|
45
46
|
</CASE>
|
46
47
|
{%- endfor %}
|
47
48
|
</CASES>
|
@@ -8,17 +8,17 @@
|
|
8
8
|
{%- import('macros/printSpecialData.xml.jinja2') as psd %}
|
9
9
|
|
10
10
|
{%- macro printParam(param) -%}
|
11
|
-
{%-
|
12
|
-
{%-
|
13
|
-
{
|
14
|
-
{
|
15
|
-
{
|
16
|
-
{%- if param.parameter_type == "TABLE-KEY" and param.odx_id is not none %}
|
17
|
-
<PARAM {{semattrib}} ID="{{param.odx_id.local_id}}" xsi:type="{{param.parameter_type}}">
|
11
|
+
{%- set semattrib = make_xml_attrib("SEMANTIC", param.semantic) -%}
|
12
|
+
{%- if param.parameter_type == "TABLE-KEY" %}
|
13
|
+
<PARAM {{ semattrib }}
|
14
|
+
{{- make_xml_attrib("ID", param.odx_id and param.odx_id.local_id) }}
|
15
|
+
xsi:type="{{param.parameter_type}}">
|
18
16
|
{%- elif param.parameter_type == "SYSTEM" %}
|
19
|
-
<PARAM
|
17
|
+
<PARAM {{ semattrib }}
|
18
|
+
{{- make_xml_attrib("SYSPARAM", param.sysparam) }}
|
19
|
+
xsi:type="{{param.parameter_type}}">
|
20
20
|
{%- else %}
|
21
|
-
<PARAM {{semattrib}} xsi:type="{{param.parameter_type}}">
|
21
|
+
<PARAM {{ semattrib }} xsi:type="{{param.parameter_type}}">
|
22
22
|
{%- endif%}
|
23
23
|
{{ peid.printElementIdSubtags(param)|indent(1) }}
|
24
24
|
{{- psd.printSpecialDataGroups(param.sdgs)|indent(1, first=True) }}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
{#- -*- mode: sgml; tab-width: 1; indent-tabs-mode: nil -*-
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
-#}
|
5
|
+
|
6
|
+
{%- import('macros/printElementId.xml.jinja2') as peid %}
|
7
|
+
|
8
|
+
{%- macro printStaticField(sf) -%}
|
9
|
+
<STATIC-FIELD ID="{{sf.odx_id.local_id}}">
|
10
|
+
{{ peid.printElementIdSubtags(sf)|indent(1) }}
|
11
|
+
<BASIC-STRUCTURE-REF ID-REF="{{sf.structure_ref.ref_id}}" />
|
12
|
+
<FIXED-NUMBER-OF-ITEMS>{{sf.fixed_number_of_items}}</FIXED-NUMBER-OF-ITEMS>
|
13
|
+
<ITEM-BYTE-SIZE>{{sf.item_byte_size}}</ITEM-BYTE-SIZE>
|
14
|
+
</STATIC-FIELD>
|
15
|
+
{%- endmacro -%}
|
@@ -9,6 +9,7 @@
|
|
9
9
|
{%- import('macros/printFunctionalClass.xml.jinja2') as pfc %}
|
10
10
|
{%- import('macros/printStructure.xml.jinja2') as pst %}
|
11
11
|
{%- import('macros/printEndOfPdu.xml.jinja2') as peopdu %}
|
12
|
+
{%- import('macros/printStaticField.xml.jinja2') as psf %}
|
12
13
|
{%- import('macros/printDynamicLengthField.xml.jinja2') as pdlf %}
|
13
14
|
{%- import('macros/printMux.xml.jinja2') as pm %}
|
14
15
|
{%- import('macros/printEnvData.xml.jinja2') as ped %}
|
@@ -67,6 +68,13 @@
|
|
67
68
|
{%- endfor %}
|
68
69
|
</STRUCTURES>
|
69
70
|
{%- endif %}
|
71
|
+
{%- if ddds.static_fields %}
|
72
|
+
<STATIC-FIELDS>
|
73
|
+
{%- for sf in ddds.static_fields %}
|
74
|
+
{{ psf.printStaticField(sf)|indent(3) }}
|
75
|
+
{%- endfor %}
|
76
|
+
</STATIC-FIELDS>
|
77
|
+
{%- endif %}
|
70
78
|
{%- if ddds.dynamic_length_fields %}
|
71
79
|
<DYNAMIC-LENGTH-FIELDS>
|
72
80
|
{%- for dlf in ddds.dynamic_length_fields %}
|
odxtools/uds.py
CHANGED
@@ -173,6 +173,6 @@ def is_response_pending(telegram_payload: bytes, request_sid: Optional[int] = No
|
|
173
173
|
|
174
174
|
|
175
175
|
# previous versions of odxtools had a typo here. hit happens!
|
176
|
-
@deprecated(details="use is_response_pending()")
|
176
|
+
@deprecated(details="use is_response_pending()") # type: ignore[misc]
|
177
177
|
def is_reponse_pending(telegram_payload: bytes, request_sid: Optional[int] = None) -> bool:
|
178
|
-
return
|
178
|
+
return is_response_pending(telegram_payload, request_sid)
|
odxtools/version.py
CHANGED
odxtools/write_pdx_file.py
CHANGED
@@ -120,15 +120,15 @@ def write_pdx_file(
|
|
120
120
|
creation_date = file_cdate.strftime("%Y-%m-%dT%H:%M:%S")
|
121
121
|
|
122
122
|
mime_type = "text/plain"
|
123
|
-
if
|
123
|
+
if output_file_name.endswith(".odx-cs"):
|
124
124
|
mime_type = "application/x-asam.odx.odx-cs"
|
125
|
-
elif
|
125
|
+
elif output_file_name.endswith(".odx-d"):
|
126
126
|
mime_type = "application/x-asam.odx.odx-d"
|
127
127
|
|
128
128
|
zf_name = os.path.basename(output_file_name)
|
129
129
|
with zf.open(zf_name, "w") as out_file:
|
130
130
|
file_index.append((zf_name, creation_date, mime_type))
|
131
|
-
out_file.write(data)
|
131
|
+
out_file.write(data)
|
132
132
|
|
133
133
|
jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(templates_dir))
|
134
134
|
jinja_env.globals["hasattr"] = hasattr
|