odxtools 6.6.1__py3-none-any.whl → 9.3.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/__init__.py +7 -5
- odxtools/additionalaudience.py +3 -5
- odxtools/admindata.py +5 -7
- odxtools/audience.py +10 -13
- odxtools/basecomparam.py +3 -5
- odxtools/basicstructure.py +55 -241
- odxtools/cli/_parser_utils.py +16 -1
- odxtools/cli/_print_utils.py +169 -134
- odxtools/cli/browse.py +127 -103
- odxtools/cli/compare.py +114 -87
- odxtools/cli/decode.py +2 -1
- odxtools/cli/dummy_sub_parser.py +3 -1
- odxtools/cli/find.py +2 -1
- odxtools/cli/list.py +26 -16
- odxtools/cli/main.py +1 -0
- odxtools/cli/snoop.py +32 -6
- odxtools/codec.py +211 -0
- odxtools/commrelation.py +122 -0
- odxtools/companydata.py +5 -7
- odxtools/companydocinfo.py +7 -8
- odxtools/companyrevisioninfo.py +3 -5
- odxtools/companyspecificinfo.py +8 -9
- odxtools/comparam.py +4 -6
- odxtools/comparaminstance.py +14 -14
- odxtools/comparamspec.py +16 -54
- odxtools/comparamsubset.py +22 -62
- odxtools/complexcomparam.py +5 -7
- odxtools/compumethods/compucodecompumethod.py +63 -0
- odxtools/compumethods/compuconst.py +31 -0
- odxtools/compumethods/compudefaultvalue.py +27 -0
- odxtools/compumethods/compuinternaltophys.py +56 -0
- odxtools/compumethods/compuinversevalue.py +7 -0
- odxtools/compumethods/compumethod.py +94 -15
- odxtools/compumethods/compuphystointernal.py +56 -0
- odxtools/compumethods/compurationalcoeffs.py +20 -9
- odxtools/compumethods/compuscale.py +67 -32
- odxtools/compumethods/createanycompumethod.py +31 -172
- odxtools/compumethods/identicalcompumethod.py +31 -6
- odxtools/compumethods/limit.py +70 -36
- odxtools/compumethods/linearcompumethod.py +70 -181
- odxtools/compumethods/linearsegment.py +190 -0
- odxtools/compumethods/ratfunccompumethod.py +106 -0
- odxtools/compumethods/ratfuncsegment.py +87 -0
- odxtools/compumethods/scalelinearcompumethod.py +132 -26
- odxtools/compumethods/scaleratfunccompumethod.py +113 -0
- odxtools/compumethods/tabintpcompumethod.py +123 -92
- odxtools/compumethods/texttablecompumethod.py +117 -57
- odxtools/createanydiagcodedtype.py +10 -67
- odxtools/database.py +167 -87
- odxtools/dataobjectproperty.py +25 -32
- odxtools/decodestate.py +14 -17
- odxtools/description.py +47 -0
- odxtools/determinenumberofitems.py +4 -5
- odxtools/diagcodedtype.py +37 -106
- odxtools/diagcomm.py +24 -12
- odxtools/diagdatadictionaryspec.py +120 -96
- odxtools/diaglayercontainer.py +46 -54
- odxtools/diaglayers/basevariant.py +128 -0
- odxtools/diaglayers/basevariantraw.py +123 -0
- odxtools/diaglayers/diaglayer.py +432 -0
- odxtools/{diaglayerraw.py → diaglayers/diaglayerraw.py} +105 -120
- odxtools/diaglayers/diaglayertype.py +42 -0
- odxtools/diaglayers/ecushareddata.py +96 -0
- odxtools/diaglayers/ecushareddataraw.py +87 -0
- odxtools/diaglayers/ecuvariant.py +124 -0
- odxtools/diaglayers/ecuvariantraw.py +129 -0
- odxtools/diaglayers/functionalgroup.py +110 -0
- odxtools/diaglayers/functionalgroupraw.py +106 -0
- odxtools/{diaglayer.py → diaglayers/hierarchyelement.py} +273 -472
- odxtools/diaglayers/hierarchyelementraw.py +58 -0
- odxtools/diaglayers/protocol.py +64 -0
- odxtools/diaglayers/protocolraw.py +91 -0
- odxtools/diagnostictroublecode.py +8 -9
- odxtools/diagservice.py +57 -44
- odxtools/diagvariable.py +113 -0
- odxtools/docrevision.py +5 -7
- odxtools/dopbase.py +15 -15
- odxtools/dtcdop.py +170 -50
- odxtools/dynamicendmarkerfield.py +134 -0
- odxtools/dynamiclengthfield.py +47 -42
- odxtools/dyndefinedspec.py +177 -0
- odxtools/dynenddopref.py +38 -0
- odxtools/ecuvariantmatcher.py +6 -7
- odxtools/element.py +13 -15
- odxtools/encodestate.py +199 -22
- odxtools/endofpdufield.py +31 -18
- odxtools/environmentdata.py +8 -1
- odxtools/environmentdatadescription.py +198 -36
- odxtools/exceptions.py +11 -2
- odxtools/field.py +10 -10
- odxtools/functionalclass.py +3 -5
- odxtools/inputparam.py +3 -12
- odxtools/internalconstr.py +14 -5
- odxtools/isotp_state_machine.py +14 -6
- odxtools/leadinglengthinfotype.py +37 -18
- odxtools/library.py +66 -0
- odxtools/loadfile.py +64 -0
- odxtools/matchingparameter.py +3 -3
- odxtools/message.py +0 -7
- odxtools/minmaxlengthtype.py +61 -33
- odxtools/modification.py +3 -5
- odxtools/multiplexer.py +135 -75
- odxtools/multiplexercase.py +39 -18
- odxtools/multiplexerdefaultcase.py +15 -12
- odxtools/multiplexerswitchkey.py +4 -5
- odxtools/nameditemlist.py +33 -8
- odxtools/negoutputparam.py +3 -5
- odxtools/odxcategory.py +83 -0
- odxtools/odxlink.py +62 -53
- odxtools/odxtypes.py +93 -8
- odxtools/outputparam.py +5 -16
- odxtools/parameterinfo.py +219 -61
- odxtools/parameters/codedconstparameter.py +45 -32
- odxtools/parameters/createanyparameter.py +19 -193
- odxtools/parameters/dynamicparameter.py +25 -4
- odxtools/parameters/lengthkeyparameter.py +83 -25
- odxtools/parameters/matchingrequestparameter.py +48 -18
- odxtools/parameters/nrcconstparameter.py +76 -54
- odxtools/parameters/parameter.py +97 -73
- odxtools/parameters/parameterwithdop.py +41 -38
- odxtools/parameters/physicalconstantparameter.py +41 -20
- odxtools/parameters/reservedparameter.py +36 -18
- odxtools/parameters/systemparameter.py +74 -7
- odxtools/parameters/tableentryparameter.py +47 -7
- odxtools/parameters/tablekeyparameter.py +142 -55
- odxtools/parameters/tablestructparameter.py +79 -58
- odxtools/parameters/valueparameter.py +39 -21
- odxtools/paramlengthinfotype.py +56 -33
- odxtools/parentref.py +20 -3
- odxtools/physicaldimension.py +3 -8
- odxtools/progcode.py +26 -11
- odxtools/protstack.py +3 -5
- odxtools/py.typed +0 -0
- odxtools/relateddoc.py +7 -9
- odxtools/request.py +120 -10
- odxtools/response.py +123 -23
- odxtools/scaleconstr.py +14 -8
- odxtools/servicebinner.py +1 -1
- odxtools/singleecujob.py +12 -10
- odxtools/snrefcontext.py +29 -0
- odxtools/specialdata.py +3 -5
- odxtools/specialdatagroup.py +7 -9
- odxtools/specialdatagroupcaption.py +3 -6
- odxtools/standardlengthtype.py +80 -14
- odxtools/state.py +3 -5
- odxtools/statechart.py +13 -19
- odxtools/statetransition.py +8 -18
- odxtools/staticfield.py +107 -0
- odxtools/subcomponent.py +288 -0
- odxtools/swvariable.py +21 -0
- odxtools/table.py +9 -9
- odxtools/tablerow.py +30 -15
- odxtools/teammember.py +3 -5
- odxtools/templates/comparam-spec.odx-c.xml.jinja2 +4 -24
- odxtools/templates/comparam-subset.odx-cs.xml.jinja2 +5 -26
- odxtools/templates/diag_layer_container.odx-d.xml.jinja2 +15 -31
- odxtools/templates/{index.xml.xml.jinja2 → index.xml.jinja2} +1 -1
- odxtools/templates/macros/printAudience.xml.jinja2 +1 -1
- odxtools/templates/macros/printBaseVariant.xml.jinja2 +53 -0
- odxtools/templates/macros/printCompanyData.xml.jinja2 +4 -7
- odxtools/templates/macros/printComparam.xml.jinja2 +6 -4
- odxtools/templates/macros/printComparamRef.xml.jinja2 +5 -12
- odxtools/templates/macros/printCompuMethod.xml.jinja2 +147 -0
- odxtools/templates/macros/printDOP.xml.jinja2 +27 -137
- odxtools/templates/macros/printDescription.xml.jinja2 +18 -0
- odxtools/templates/macros/printDiagComm.xml.jinja2 +1 -1
- odxtools/templates/macros/printDiagLayer.xml.jinja2 +222 -0
- odxtools/templates/macros/printDiagVariable.xml.jinja2 +66 -0
- odxtools/templates/macros/printDynDefinedSpec.xml.jinja2 +48 -0
- odxtools/templates/macros/printDynamicEndmarkerField.xml.jinja2 +16 -0
- odxtools/templates/macros/printDynamicLengthField.xml.jinja2 +1 -1
- odxtools/templates/macros/printEcuSharedData.xml.jinja2 +30 -0
- odxtools/templates/macros/printEcuVariant.xml.jinja2 +53 -0
- odxtools/templates/macros/printEcuVariantPattern.xml.jinja2 +1 -1
- odxtools/templates/macros/printElementId.xml.jinja2 +8 -3
- odxtools/templates/macros/printEndOfPdu.xml.jinja2 +1 -1
- odxtools/templates/macros/printEnvDataDesc.xml.jinja2 +1 -1
- odxtools/templates/macros/printFunctionalClass.xml.jinja2 +1 -1
- odxtools/templates/macros/printFunctionalGroup.xml.jinja2 +40 -0
- odxtools/templates/macros/printHierarchyElement.xml.jinja2 +24 -0
- odxtools/templates/macros/printLibrary.xml.jinja2 +21 -0
- odxtools/templates/macros/printMux.xml.jinja2 +5 -3
- odxtools/templates/macros/printOdxCategory.xml.jinja2 +28 -0
- odxtools/templates/macros/printParam.xml.jinja2 +18 -19
- odxtools/templates/macros/printProtStack.xml.jinja2 +1 -1
- odxtools/templates/macros/printProtocol.xml.jinja2 +30 -0
- odxtools/templates/macros/printRequest.xml.jinja2 +1 -1
- odxtools/templates/macros/printResponse.xml.jinja2 +1 -1
- odxtools/templates/macros/printService.xml.jinja2 +3 -2
- odxtools/templates/macros/printSingleEcuJob.xml.jinja2 +5 -26
- odxtools/templates/macros/printSpecialData.xml.jinja2 +1 -1
- odxtools/templates/macros/printState.xml.jinja2 +1 -1
- odxtools/templates/macros/printStateChart.xml.jinja2 +1 -1
- odxtools/templates/macros/printStateTransition.xml.jinja2 +1 -1
- odxtools/templates/macros/printStaticField.xml.jinja2 +15 -0
- odxtools/templates/macros/printStructure.xml.jinja2 +1 -1
- odxtools/templates/macros/printSubComponent.xml.jinja2 +104 -0
- odxtools/templates/macros/printTable.xml.jinja2 +4 -5
- odxtools/templates/macros/printUnitSpec.xml.jinja2 +3 -5
- odxtools/uds.py +2 -10
- odxtools/unit.py +4 -8
- odxtools/unitgroup.py +3 -5
- odxtools/unitspec.py +17 -17
- odxtools/utils.py +38 -20
- odxtools/variablegroup.py +32 -0
- odxtools/version.py +2 -2
- odxtools/{write_pdx_file.py → writepdxfile.py} +22 -12
- odxtools/xdoc.py +3 -5
- {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/METADATA +44 -33
- odxtools-9.3.0.dist-info/RECORD +228 -0
- {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/WHEEL +1 -1
- odxtools/createcompanydatas.py +0 -17
- odxtools/createsdgs.py +0 -19
- odxtools/diaglayertype.py +0 -30
- odxtools/load_file.py +0 -13
- odxtools/load_odx_d_file.py +0 -6
- odxtools/load_pdx_file.py +0 -8
- odxtools/templates/macros/printVariant.xml.jinja2 +0 -208
- odxtools-6.6.1.dist-info/RECORD +0 -180
- {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/LICENSE +0 -0
- {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/entry_points.txt +0 -0
- {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/top_level.txt +0 -0
odxtools/odxtypes.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from enum import Enum
|
3
|
-
from typing import TYPE_CHECKING, Any, Callable, Dict,
|
3
|
+
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, Optional, Tuple, Type, Union,
|
4
|
+
overload)
|
4
5
|
from xml.etree import ElementTree
|
5
6
|
|
6
7
|
from .exceptions import odxassert, odxraise, odxrequire
|
@@ -28,7 +29,7 @@ ParameterDict = Dict[str, Union["Parameter", "ParameterDict"]]
|
|
28
29
|
# multiple items, so this can be a list of objects.
|
29
30
|
TableStructParameterValue = Tuple[str, "ParameterValue"]
|
30
31
|
ParameterValue = Union[AtomicOdxType, "ParameterValueDict", TableStructParameterValue,
|
31
|
-
|
32
|
+
Iterable["ParameterValue"], "DiagnosticTroubleCode"]
|
32
33
|
ParameterValueDict = Dict[str, ParameterValue]
|
33
34
|
|
34
35
|
|
@@ -63,8 +64,8 @@ def bool_to_odxstr(bool_val: bool) -> str:
|
|
63
64
|
|
64
65
|
def parse_int(value: str) -> int:
|
65
66
|
try:
|
66
|
-
return int(value)
|
67
|
-
except ValueError:
|
67
|
+
return int(value, 0)
|
68
|
+
except (ValueError, TypeError):
|
68
69
|
try:
|
69
70
|
v = float(value)
|
70
71
|
except Exception as e:
|
@@ -102,6 +103,71 @@ _ODX_TYPE_TO_PYTHON_TYPE: Dict[str, Type[AtomicOdxType]] = {
|
|
102
103
|
}
|
103
104
|
|
104
105
|
|
106
|
+
def compare_odx_values(a: AtomicOdxType, b: AtomicOdxType) -> int:
|
107
|
+
# this function implements the comparison according to the ODX
|
108
|
+
# specification. (cf section 7.3.6.5)
|
109
|
+
|
110
|
+
# numeric values are compared numerically (duh!)
|
111
|
+
if isinstance(a, (int, float)):
|
112
|
+
if not isinstance(b, (int, float)):
|
113
|
+
odxraise()
|
114
|
+
|
115
|
+
tmp = a - b
|
116
|
+
if tmp < 0:
|
117
|
+
return -1
|
118
|
+
elif tmp > 0:
|
119
|
+
return 1
|
120
|
+
return 0
|
121
|
+
|
122
|
+
# strings are compared lexicographically. (the spec only allows
|
123
|
+
# equals, but this cannot easily implemented using a single
|
124
|
+
# comparison function.
|
125
|
+
if isinstance(a, str):
|
126
|
+
if not isinstance(b, str):
|
127
|
+
odxraise()
|
128
|
+
|
129
|
+
if a < b:
|
130
|
+
return -1
|
131
|
+
elif b < a:
|
132
|
+
return 1
|
133
|
+
else:
|
134
|
+
return 0
|
135
|
+
|
136
|
+
# bytefields are treated like long integers: to pad the shorter
|
137
|
+
# object with zeros and treat the results like strings.
|
138
|
+
if isinstance(a, (bytes, bytearray)):
|
139
|
+
if not isinstance(b, (bytes, bytearray)):
|
140
|
+
odxraise()
|
141
|
+
|
142
|
+
obj_len = max(len(a), len(b))
|
143
|
+
|
144
|
+
tmp_a = a.ljust(obj_len, b'\x00')
|
145
|
+
tmp_b = b.ljust(obj_len, b'\x00')
|
146
|
+
|
147
|
+
if tmp_a > tmp_b:
|
148
|
+
return 1
|
149
|
+
elif tmp_a < tmp_b:
|
150
|
+
return -1
|
151
|
+
else:
|
152
|
+
return 0
|
153
|
+
|
154
|
+
odxraise(f"Unhandled comparsion between objects of type {type(a).__name__} "
|
155
|
+
f"and {type(b).__name__}")
|
156
|
+
|
157
|
+
|
158
|
+
# format specifiers for the data type using the bitstruct module
|
159
|
+
_BITSTRUCT_FORMAT_LETTER_MAP__ = {
|
160
|
+
"A_INT32": "s",
|
161
|
+
"A_UINT32": "u",
|
162
|
+
"A_FLOAT32": "f",
|
163
|
+
"A_FLOAT64": "f",
|
164
|
+
"A_BYTEFIELD": "r",
|
165
|
+
"A_UNICODE2STRING": "r", # UTF-16 strings must be converted explicitly
|
166
|
+
"A_ASCIISTRING": "r",
|
167
|
+
"A_UTF8STRING": "r",
|
168
|
+
}
|
169
|
+
|
170
|
+
|
105
171
|
class DataType(Enum):
|
106
172
|
"""Types for the physical and internal value.
|
107
173
|
|
@@ -125,9 +191,14 @@ class DataType(Enum):
|
|
125
191
|
A_ASCIISTRING = "A_ASCIISTRING"
|
126
192
|
A_UTF8STRING = "A_UTF8STRING"
|
127
193
|
|
128
|
-
|
194
|
+
@property
|
195
|
+
def python_type(self) -> Type[AtomicOdxType]:
|
129
196
|
return _ODX_TYPE_TO_PYTHON_TYPE[self.value]
|
130
197
|
|
198
|
+
@property
|
199
|
+
def bitstruct_format_letter(self) -> str:
|
200
|
+
return _BITSTRUCT_FORMAT_LETTER_MAP__[self.value]
|
201
|
+
|
131
202
|
def from_string(self, value: str) -> AtomicOdxType:
|
132
203
|
return _PARSE_ODX_TYPE[self.value](value)
|
133
204
|
|
@@ -158,15 +229,29 @@ class DataType(Enum):
|
|
158
229
|
return self.from_string(value)
|
159
230
|
else:
|
160
231
|
# regular type cast of python objects
|
161
|
-
return self.
|
232
|
+
return self.python_type(value)
|
162
233
|
|
163
234
|
def isinstance(self, value: Any) -> bool:
|
164
|
-
expected_type = self.
|
235
|
+
expected_type = self.python_type
|
165
236
|
if isinstance(value, expected_type):
|
166
237
|
return True
|
167
|
-
elif expected_type
|
238
|
+
elif expected_type is float and isinstance(value, (int, float)):
|
168
239
|
return True
|
169
240
|
elif self == DataType.A_BYTEFIELD and isinstance(value, (bytearray, bytes)):
|
170
241
|
return True
|
171
242
|
else:
|
172
243
|
return False
|
244
|
+
|
245
|
+
def __str__(self) -> str:
|
246
|
+
if self == DataType.A_INT32:
|
247
|
+
return "int"
|
248
|
+
elif self == DataType.A_UINT32:
|
249
|
+
return "uint"
|
250
|
+
elif self in (DataType.A_FLOAT32, DataType.A_FLOAT64):
|
251
|
+
return "float"
|
252
|
+
elif self == DataType.A_BYTEFIELD:
|
253
|
+
return "bytefield"
|
254
|
+
elif self in (DataType.A_UNICODE2STRING, DataType.A_ASCIISTRING, DataType.A_UTF8STRING):
|
255
|
+
return "string"
|
256
|
+
else:
|
257
|
+
return f"<unknown type '{self.value}'>"
|
odxtools/outputparam.py
CHANGED
@@ -1,24 +1,19 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
-
from deprecation import deprecated
|
7
|
-
|
8
6
|
from .dopbase import DopBase
|
9
7
|
from .element import IdentifiableElement
|
10
8
|
from .exceptions import odxrequire
|
11
9
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
10
|
+
from .snrefcontext import SnRefContext
|
12
11
|
from .utils import dataclass_fields_asdict
|
13
12
|
|
14
|
-
if TYPE_CHECKING:
|
15
|
-
from .diaglayer import DiagLayer
|
16
|
-
|
17
13
|
|
18
14
|
@dataclass
|
19
15
|
class OutputParam(IdentifiableElement):
|
20
16
|
dop_base_ref: OdxLinkRef
|
21
|
-
oid: Optional[str]
|
22
17
|
semantic: Optional[str]
|
23
18
|
|
24
19
|
@staticmethod
|
@@ -27,25 +22,19 @@ class OutputParam(IdentifiableElement):
|
|
27
22
|
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
28
23
|
dop_base_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DOP-BASE-REF"), doc_frags))
|
29
24
|
semantic = et_element.get("SEMANTIC")
|
30
|
-
oid = et_element.get("OID")
|
31
25
|
|
32
|
-
return OutputParam(dop_base_ref=dop_base_ref, semantic=semantic,
|
26
|
+
return OutputParam(dop_base_ref=dop_base_ref, semantic=semantic, **kwargs)
|
33
27
|
|
34
28
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
35
29
|
return {}
|
36
30
|
|
37
31
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
38
|
-
self._dop_base = odxlinks.resolve(self.dop_base_ref)
|
32
|
+
self._dop_base = odxlinks.resolve(self.dop_base_ref, DopBase)
|
39
33
|
|
40
|
-
def _resolve_snrefs(self,
|
34
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
41
35
|
pass
|
42
36
|
|
43
37
|
@property
|
44
38
|
def dop_base(self) -> DopBase:
|
45
39
|
"""The data object property describing this parameter."""
|
46
40
|
return self._dop_base
|
47
|
-
|
48
|
-
@property
|
49
|
-
@deprecated(details="use .dop_base")
|
50
|
-
def dop(self) -> DopBase:
|
51
|
-
return self._dop_base
|
odxtools/parameterinfo.py
CHANGED
@@ -1,98 +1,256 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
-
import
|
3
|
-
from
|
2
|
+
import textwrap
|
3
|
+
from io import StringIO
|
4
|
+
from typing import Iterable
|
4
5
|
|
6
|
+
from .compumethods.compucodecompumethod import CompuCodeCompuMethod
|
5
7
|
from .compumethods.identicalcompumethod import IdenticalCompuMethod
|
6
8
|
from .compumethods.limit import IntervalType
|
7
9
|
from .compumethods.linearcompumethod import LinearCompuMethod
|
10
|
+
from .compumethods.linearsegment import LinearSegment
|
11
|
+
from .compumethods.ratfunccompumethod import RatFuncCompuMethod
|
12
|
+
from .compumethods.ratfuncsegment import RatFuncSegment
|
13
|
+
from .compumethods.scalelinearcompumethod import ScaleLinearCompuMethod
|
14
|
+
from .compumethods.scaleratfunccompumethod import ScaleRatFuncCompuMethod
|
8
15
|
from .compumethods.texttablecompumethod import TexttableCompuMethod
|
9
16
|
from .dataobjectproperty import DataObjectProperty
|
17
|
+
from .dtcdop import DtcDop
|
18
|
+
from .dynamiclengthfield import DynamicLengthField
|
10
19
|
from .endofpdufield import EndOfPduField
|
11
|
-
from .
|
20
|
+
from .exceptions import odxrequire
|
21
|
+
from .multiplexer import Multiplexer
|
12
22
|
from .parameters.codedconstparameter import CodedConstParameter
|
13
23
|
from .parameters.matchingrequestparameter import MatchingRequestParameter
|
24
|
+
from .parameters.nrcconstparameter import NrcConstParameter
|
14
25
|
from .parameters.parameter import Parameter
|
15
26
|
from .parameters.parameterwithdop import ParameterWithDOP
|
16
27
|
from .parameters.reservedparameter import ReservedParameter
|
28
|
+
from .parameters.systemparameter import SystemParameter
|
29
|
+
from .parameters.tablekeyparameter import TableKeyParameter
|
30
|
+
from .parameters.tablestructparameter import TableStructParameter
|
31
|
+
from .paramlengthinfotype import ParamLengthInfoType
|
32
|
+
from .staticfield import StaticField
|
17
33
|
|
18
34
|
|
19
|
-
def
|
20
|
-
|
35
|
+
def _get_linear_segment_info(segment: LinearSegment) -> str:
|
36
|
+
ll = segment.physical_lower_limit
|
37
|
+
if ll is None or ll.interval_type == IntervalType.INFINITE:
|
38
|
+
ll_str = "(-inf"
|
39
|
+
else:
|
40
|
+
ll_delim = '(' if ll.interval_type == IntervalType.OPEN else '['
|
41
|
+
ll_str = f"{ll_delim}{ll._value!r}"
|
42
|
+
|
43
|
+
ul = segment.physical_upper_limit
|
44
|
+
if ul is None or ul.interval_type == IntervalType.INFINITE:
|
45
|
+
ul_str = "inf)"
|
46
|
+
else:
|
47
|
+
ul_delim = ')' if ul.interval_type == IntervalType.OPEN else ']'
|
48
|
+
ul_str = f"{ul._value!r}{ul_delim}"
|
49
|
+
|
50
|
+
return f"{ll_str}, {ul_str}"
|
51
|
+
|
52
|
+
|
53
|
+
def _get_rat_func_segment_info(segment: RatFuncSegment) -> str:
|
54
|
+
ll = segment.lower_limit
|
55
|
+
if ll is None or ll.interval_type == IntervalType.INFINITE:
|
56
|
+
ll_str = "(-inf"
|
57
|
+
else:
|
58
|
+
ll_delim = '(' if ll.interval_type == IntervalType.OPEN else '['
|
59
|
+
ll_str = f"{ll_delim}{ll._value!r}"
|
60
|
+
|
61
|
+
ul = segment.upper_limit
|
62
|
+
if ul is None or ul.interval_type == IntervalType.INFINITE:
|
63
|
+
ul_str = "inf)"
|
64
|
+
else:
|
65
|
+
ul_delim = ')' if ul.interval_type == IntervalType.OPEN else ']'
|
66
|
+
ul_str = f"{ul._value!r}{ul_delim}"
|
67
|
+
|
68
|
+
return f"{ll_str}, {ul_str}"
|
69
|
+
|
70
|
+
|
71
|
+
def parameter_info(param_list: Iterable[Parameter], quoted_names: bool = False) -> str:
|
72
|
+
q = "'" if quoted_names else ""
|
73
|
+
of = StringIO()
|
21
74
|
for param in param_list:
|
22
75
|
if isinstance(param, CodedConstParameter):
|
23
|
-
|
76
|
+
of.write(f"{q}{param.short_name}{q}: const = {param._coded_value_str}\n")
|
24
77
|
continue
|
25
78
|
elif isinstance(param, MatchingRequestParameter):
|
26
|
-
|
79
|
+
of.write(f"{q}{param.short_name}{q}: <matches request>\n")
|
80
|
+
continue
|
81
|
+
elif isinstance(param, NrcConstParameter):
|
82
|
+
of.write(f"{q}{param.short_name}{q}: const; choices = {param.coded_values}\n")
|
27
83
|
continue
|
28
84
|
elif isinstance(param, ReservedParameter):
|
29
|
-
|
85
|
+
of.write(f"{q}{param.short_name}{q}: <reserved>\n")
|
30
86
|
continue
|
31
|
-
elif
|
32
|
-
|
87
|
+
elif isinstance(param, SystemParameter):
|
88
|
+
of.write(
|
89
|
+
f"{q}{param.short_name}{q}: <system; kind = \"{param.sysparam}\">; required = {param.is_required}\n"
|
90
|
+
)
|
33
91
|
continue
|
92
|
+
elif isinstance(param, TableKeyParameter):
|
93
|
+
of.write(
|
94
|
+
f"{q}{param.short_name}{q}: <optional> table key; table = '{param.table.short_name}'; choices:\n"
|
95
|
+
)
|
96
|
+
for tr in param.table.table_rows:
|
97
|
+
of.write(f" '{tr.short_name}',\n")
|
34
98
|
|
35
|
-
dop = param.dop
|
36
|
-
|
37
|
-
if isinstance(dop, EndOfPduField):
|
38
|
-
result += f"{param.short_name} : <optional> list({{\n"
|
39
|
-
tmp = parameter_info(dop.structure.parameters).strip()
|
40
|
-
tmp = re.sub("^", " ", tmp)
|
41
|
-
result += tmp + "\n"
|
42
|
-
result += f"}})\n"
|
43
99
|
continue
|
100
|
+
elif isinstance(param, TableStructParameter):
|
101
|
+
of.write(
|
102
|
+
f"{q}{param.short_name}{q}: table struct; key = '{param.table_key.short_name}'; choices:\n"
|
103
|
+
)
|
104
|
+
for tr in param.table_key.table.table_rows:
|
105
|
+
of.write(f" ('{tr.short_name}',\n")
|
106
|
+
of.write(f" {{\n")
|
107
|
+
of.write(
|
108
|
+
textwrap.indent(
|
109
|
+
parameter_info(odxrequire(tr.structure).parameters, True), " "))
|
110
|
+
of.write(f" }}),\n")
|
44
111
|
|
45
|
-
|
112
|
+
continue
|
113
|
+
elif not isinstance(param, ParameterWithDOP):
|
114
|
+
of.write(
|
115
|
+
f"{q}{param.short_name}{q}: <unhandled parameter type '{type(param).__name__}'>\n")
|
116
|
+
continue
|
46
117
|
|
118
|
+
dop = param.dop
|
47
119
|
if dop is None:
|
48
|
-
|
120
|
+
of.write("{q}{param.short_name}{q}: <no DOP>\n")
|
49
121
|
continue
|
50
|
-
elif
|
51
|
-
|
122
|
+
elif isinstance(dop, EndOfPduField):
|
123
|
+
of.write(f"{q}{param.short_name}{q}: list({{\n")
|
124
|
+
of.write(textwrap.indent(parameter_info(dop.structure.parameters, True), " "))
|
125
|
+
of.write(f"}})\n")
|
52
126
|
continue
|
53
|
-
|
54
|
-
|
55
|
-
|
127
|
+
elif isinstance(dop, StaticField):
|
128
|
+
of.write(f"{q}{param.short_name}{q}: length={dop.fixed_number_of_items}; list({{\n")
|
129
|
+
of.write(textwrap.indent(parameter_info(dop.structure.parameters, True), " "))
|
130
|
+
of.write(f"}})\n")
|
131
|
+
continue
|
132
|
+
elif isinstance(dop, DynamicLengthField):
|
133
|
+
of.write(f"{q}{param.short_name}{q}: list({{\n")
|
134
|
+
of.write(textwrap.indent(parameter_info(dop.structure.parameters, True), " "))
|
135
|
+
of.write(f"}})\n")
|
56
136
|
continue
|
137
|
+
elif isinstance(dop, ParamLengthInfoType):
|
138
|
+
of.write(f"{q}{param.short_name}{q}: ")
|
139
|
+
of.write("<optional> ")
|
140
|
+
of.write(f"int; length_key='{dop.length_key.short_name}'\n")
|
141
|
+
continue
|
142
|
+
elif isinstance(dop, DtcDop):
|
143
|
+
of.write(f"{q}{param.short_name}{q}: ")
|
144
|
+
of.write(f"DTC; choices:\n")
|
145
|
+
for dtc in dop.dtcs:
|
146
|
+
if dtc.display_trouble_code is not None:
|
147
|
+
dtc_desc = dtc.text and f"; \"{dtc.text}\""
|
148
|
+
of.write(
|
149
|
+
f" '{dtc.display_trouble_code}' (0x{dtc.trouble_code:06x}{dtc_desc})\n")
|
150
|
+
else:
|
151
|
+
dtc_desc = dtc.text and f" (\"{dtc.text}\")"
|
152
|
+
of.write(f" 0x{dtc.trouble_code:06x}{dtc_desc}\n")
|
153
|
+
continue
|
154
|
+
elif isinstance(dop, Multiplexer):
|
155
|
+
of.write(f"{q}{param.short_name}{q}: ")
|
156
|
+
if dop.default_case is not None:
|
157
|
+
of.write(f"<optional>")
|
158
|
+
of.write(f"multiplexer; choices:\n")
|
159
|
+
for mux_case in dop.cases:
|
160
|
+
of.write(f" ({repr(mux_case.short_name)}, {{\n")
|
161
|
+
if (struc := mux_case.structure) is not None:
|
162
|
+
of.write(textwrap.indent(parameter_info(struc.parameters, True), " "))
|
163
|
+
of.write(f" }})\n")
|
164
|
+
continue
|
165
|
+
elif isinstance(dop, DataObjectProperty):
|
166
|
+
# a "simple" DOP
|
167
|
+
if (cm := dop.compu_method) is None:
|
168
|
+
of.write(f"{q}{param.short_name}{q}: <no compu method>\n")
|
169
|
+
continue
|
57
170
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
171
|
+
if isinstance(cm, TexttableCompuMethod):
|
172
|
+
of.write(f"{q}{param.short_name}{q}: enum; choices:\n")
|
173
|
+
for scale in odxrequire(cm.compu_internal_to_phys).compu_scales:
|
174
|
+
val_str = ""
|
175
|
+
if scale.lower_limit is not None:
|
176
|
+
val_str = f"({repr(scale.lower_limit.value)})"
|
177
|
+
|
178
|
+
if scale.compu_const is None:
|
179
|
+
of.write(f" <ERROR in ODX data: no value specified>\n")
|
180
|
+
else:
|
181
|
+
vt = scale.compu_const.vt
|
182
|
+
v = scale.compu_const.v
|
183
|
+
if vt is not None:
|
184
|
+
of.write(f" \"{vt}\" {val_str}\n")
|
185
|
+
else:
|
186
|
+
of.write(f" {v}\n")
|
187
|
+
|
188
|
+
elif isinstance(cm, IdenticalCompuMethod):
|
189
|
+
of.write(f"{q}{param.short_name}{q}: {dop.physical_type.base_data_type}\n")
|
190
|
+
|
191
|
+
elif isinstance(cm, ScaleLinearCompuMethod):
|
192
|
+
of.write(f"{q}{param.short_name}{q}: {dop.physical_type.base_data_type}")
|
193
|
+
seg_list = [_get_linear_segment_info(x) for x in cm.segments]
|
194
|
+
of.write(f"; ranges = {{ {', '.join(seg_list)} }}")
|
195
|
+
|
196
|
+
unit = dop.unit
|
197
|
+
unit_str = unit.display_name if unit is not None else None
|
198
|
+
if unit_str is not None:
|
199
|
+
of.write(f"; unit: {unit_str}")
|
200
|
+
|
201
|
+
of.write("\n")
|
77
202
|
|
78
|
-
|
79
|
-
|
203
|
+
elif isinstance(cm, LinearCompuMethod):
|
204
|
+
of.write(f"{q}{param.short_name}{q}: {dop.physical_type.base_data_type}")
|
205
|
+
of.write(f"; range: {_get_linear_segment_info(cm.segment)}")
|
80
206
|
|
81
|
-
|
207
|
+
unit = dop.unit
|
208
|
+
unit_str = unit.display_name if unit is not None else None
|
209
|
+
if unit_str is not None:
|
210
|
+
of.write(f"; unit: {unit_str}")
|
82
211
|
|
83
|
-
|
84
|
-
result += f": float\n"
|
85
|
-
ll = cm.physical_lower_limit
|
86
|
-
ul = cm.physical_upper_limit
|
87
|
-
result += (f" range: "
|
88
|
-
f"{'[' if ll.interval_type == IntervalType.CLOSED else '('}"
|
89
|
-
f"{ll.value!r}, "
|
90
|
-
f"{ul.value!r}"
|
91
|
-
f"{']' if ul.interval_type == IntervalType.CLOSED else ')'}\n")
|
212
|
+
of.write("\n")
|
92
213
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
214
|
+
elif isinstance(cm, ScaleRatFuncCompuMethod):
|
215
|
+
of.write(f"{q}{param.short_name}{q}: {dop.physical_type.base_data_type}")
|
216
|
+
if cm._phys_to_int_segments is None:
|
217
|
+
of.write("<NOT ENCODABLE>")
|
218
|
+
else:
|
219
|
+
seg_list = [_get_rat_func_segment_info(x) for x in cm._phys_to_int_segments]
|
220
|
+
of.write(f"; ranges = {{ {', '.join(seg_list)} }}")
|
221
|
+
|
222
|
+
unit = dop.unit
|
223
|
+
unit_str = unit.display_name if unit is not None else None
|
224
|
+
if unit_str is not None:
|
225
|
+
of.write(f"; unit: {unit_str}")
|
226
|
+
|
227
|
+
of.write("\n")
|
228
|
+
|
229
|
+
elif isinstance(cm, RatFuncCompuMethod):
|
230
|
+
of.write(f"{q}{param.short_name}{q}: {dop.physical_type.base_data_type}")
|
231
|
+
if cm._phys_to_int_segment is None:
|
232
|
+
of.write("<NOT ENCODABLE>")
|
233
|
+
else:
|
234
|
+
of.write(f"; range: {_get_rat_func_segment_info(cm._phys_to_int_segment)}")
|
235
|
+
|
236
|
+
unit = dop.unit
|
237
|
+
unit_str = unit.display_name if unit is not None else None
|
238
|
+
if unit_str is not None:
|
239
|
+
of.write(f"; unit: {unit_str}")
|
240
|
+
|
241
|
+
of.write("\n")
|
242
|
+
|
243
|
+
elif isinstance(cm, CompuCodeCompuMethod):
|
244
|
+
of.write(f"{q}{param.short_name}{q}: {dop.physical_type.base_data_type}")
|
245
|
+
of.write(f"; <programmatic translation>")
|
246
|
+
|
247
|
+
of.write("\n")
|
248
|
+
|
249
|
+
else:
|
250
|
+
of.write(
|
251
|
+
f"{q}{param.short_name}{q}: unknown compu method {type(dop.compu_method).__name__}\n"
|
252
|
+
)
|
253
|
+
else:
|
254
|
+
of.write(f"{q}{param.short_name}{q}: <unhandled DOP '{type(dop).__name__}'>\n")
|
97
255
|
|
98
|
-
return
|
256
|
+
return of.getvalue()
|
@@ -1,19 +1,21 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
import warnings
|
3
3
|
from dataclasses import dataclass
|
4
|
-
from typing import
|
4
|
+
from typing import Any, Dict, List, Optional
|
5
|
+
from xml.etree import ElementTree
|
5
6
|
|
7
|
+
from typing_extensions import override
|
8
|
+
|
9
|
+
from ..createanydiagcodedtype import create_any_diag_coded_type_from_et
|
6
10
|
from ..decodestate import DecodeState
|
7
11
|
from ..diagcodedtype import DiagCodedType
|
8
12
|
from ..encodestate import EncodeState
|
9
|
-
from ..exceptions import DecodeError
|
10
|
-
from ..odxlink import
|
11
|
-
from ..odxtypes import AtomicOdxType, DataType
|
13
|
+
from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
|
14
|
+
from ..odxlink import OdxDocFragment, OdxLinkId
|
15
|
+
from ..odxtypes import AtomicOdxType, DataType, ParameterValue
|
16
|
+
from ..utils import dataclass_fields_asdict
|
12
17
|
from .parameter import Parameter, ParameterType
|
13
18
|
|
14
|
-
if TYPE_CHECKING:
|
15
|
-
from ..diaglayer import DiagLayer
|
16
|
-
|
17
19
|
|
18
20
|
@dataclass
|
19
21
|
class CodedConstParameter(Parameter):
|
@@ -21,10 +23,27 @@ class CodedConstParameter(Parameter):
|
|
21
23
|
diag_coded_type: DiagCodedType
|
22
24
|
coded_value: AtomicOdxType
|
23
25
|
|
26
|
+
@staticmethod
|
27
|
+
@override
|
28
|
+
def from_et(et_element: ElementTree.Element,
|
29
|
+
doc_frags: List[OdxDocFragment]) -> "CodedConstParameter":
|
30
|
+
|
31
|
+
kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
|
32
|
+
|
33
|
+
dct_elem = odxrequire(et_element.find("DIAG-CODED-TYPE"))
|
34
|
+
diag_coded_type = create_any_diag_coded_type_from_et(dct_elem, doc_frags)
|
35
|
+
coded_value = diag_coded_type.base_data_type.from_string(
|
36
|
+
odxrequire(et_element.findtext("CODED-VALUE")))
|
37
|
+
|
38
|
+
return CodedConstParameter(
|
39
|
+
diag_coded_type=diag_coded_type, coded_value=coded_value, **kwargs)
|
40
|
+
|
24
41
|
@property
|
42
|
+
@override
|
25
43
|
def parameter_type(self) -> ParameterType:
|
26
44
|
return "CODED-CONST"
|
27
45
|
|
46
|
+
@override
|
28
47
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
29
48
|
result = super()._build_odxlinks()
|
30
49
|
|
@@ -32,12 +51,7 @@ class CodedConstParameter(Parameter):
|
|
32
51
|
|
33
52
|
return result
|
34
53
|
|
35
|
-
|
36
|
-
super()._resolve_odxlinks(odxlinks)
|
37
|
-
|
38
|
-
def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
|
39
|
-
super()._resolve_snrefs(diag_layer)
|
40
|
-
|
54
|
+
@override
|
41
55
|
def get_static_bit_length(self) -> Optional[int]:
|
42
56
|
return self.diag_coded_type.get_static_bit_length()
|
43
57
|
|
@@ -46,32 +60,33 @@ class CodedConstParameter(Parameter):
|
|
46
60
|
return self.diag_coded_type.base_data_type
|
47
61
|
|
48
62
|
@property
|
63
|
+
@override
|
49
64
|
def is_required(self) -> bool:
|
50
65
|
return False
|
51
66
|
|
52
67
|
@property
|
68
|
+
@override
|
53
69
|
def is_settable(self) -> bool:
|
54
70
|
return False
|
55
71
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
decode_state.cursor_bit_position = self.bit_position or 0
|
72
|
+
@override
|
73
|
+
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
74
|
+
encode_state: EncodeState) -> None:
|
75
|
+
if physical_value is not None and physical_value != self.coded_value:
|
76
|
+
odxraise(
|
77
|
+
f"Value for constant parameter `{self.short_name}` name can "
|
78
|
+
f"only be specified as {self.coded_value!r} (is: {physical_value!r})", EncodeError)
|
79
|
+
|
80
|
+
internal_value = self.coded_value
|
81
|
+
|
82
|
+
self.diag_coded_type.encode_into_pdu(
|
83
|
+
internal_value=internal_value, encode_state=encode_state)
|
84
|
+
|
85
|
+
@override
|
86
|
+
def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> AtomicOdxType:
|
72
87
|
coded_val = self.diag_coded_type.decode_from_pdu(decode_state)
|
73
88
|
|
74
|
-
# Check if the coded value
|
89
|
+
# Check if the coded value contained by the message is correct.
|
75
90
|
if self.coded_value != coded_val:
|
76
91
|
warnings.warn(
|
77
92
|
f"Coded constant parameter does not match! "
|
@@ -83,8 +98,6 @@ class CodedConstParameter(Parameter):
|
|
83
98
|
stacklevel=1,
|
84
99
|
)
|
85
100
|
|
86
|
-
decode_state.cursor_byte_position = max(orig_cursor_pos, decode_state.cursor_byte_position)
|
87
|
-
|
88
101
|
return coded_val
|
89
102
|
|
90
103
|
@property
|