odxtools 6.7.0__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 +6 -4
- odxtools/additionalaudience.py +3 -5
- odxtools/admindata.py +5 -7
- odxtools/audience.py +10 -13
- odxtools/basecomparam.py +3 -5
- odxtools/basicstructure.py +55 -240
- odxtools/cli/_parser_utils.py +1 -1
- odxtools/cli/_print_utils.py +168 -134
- odxtools/cli/browse.py +111 -92
- odxtools/cli/compare.py +90 -71
- odxtools/cli/list.py +24 -15
- odxtools/cli/snoop.py +28 -5
- 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 +7 -9
- 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 +93 -12
- odxtools/compumethods/compuphystointernal.py +56 -0
- odxtools/compumethods/compurationalcoeffs.py +20 -9
- odxtools/compumethods/compuscale.py +30 -35
- odxtools/compumethods/createanycompumethod.py +28 -161
- odxtools/compumethods/identicalcompumethod.py +31 -6
- odxtools/compumethods/linearcompumethod.py +69 -189
- 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 +119 -99
- odxtools/compumethods/texttablecompumethod.py +107 -43
- odxtools/createanydiagcodedtype.py +10 -67
- odxtools/database.py +167 -87
- odxtools/dataobjectproperty.py +15 -25
- odxtools/decodestate.py +9 -15
- odxtools/description.py +47 -0
- odxtools/determinenumberofitems.py +4 -5
- odxtools/diagcodedtype.py +36 -106
- odxtools/diagcomm.py +24 -12
- odxtools/diagdatadictionaryspec.py +33 -34
- 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/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} +209 -448
- 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 +56 -43
- odxtools/diagvariable.py +113 -0
- odxtools/docrevision.py +5 -7
- odxtools/dopbase.py +15 -17
- odxtools/dtcdop.py +168 -50
- odxtools/dynamicendmarkerfield.py +134 -0
- odxtools/dynamiclengthfield.py +41 -37
- 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 -38
- odxtools/exceptions.py +11 -2
- odxtools/field.py +10 -10
- odxtools/functionalclass.py +3 -5
- odxtools/inputparam.py +3 -12
- 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 +128 -73
- odxtools/multiplexercase.py +13 -14
- odxtools/multiplexerdefaultcase.py +15 -12
- odxtools/multiplexerswitchkey.py +4 -5
- odxtools/nameditemlist.py +29 -5
- odxtools/negoutputparam.py +3 -5
- odxtools/odxcategory.py +83 -0
- odxtools/odxlink.py +60 -51
- odxtools/odxtypes.py +37 -5
- odxtools/outputparam.py +4 -15
- odxtools/parameterinfo.py +218 -67
- odxtools/parameters/codedconstparameter.py +16 -24
- odxtools/parameters/dynamicparameter.py +5 -4
- odxtools/parameters/lengthkeyparameter.py +60 -26
- odxtools/parameters/matchingrequestparameter.py +23 -11
- odxtools/parameters/nrcconstparameter.py +45 -46
- odxtools/parameters/parameter.py +54 -56
- odxtools/parameters/parameterwithdop.py +15 -25
- odxtools/parameters/physicalconstantparameter.py +15 -18
- odxtools/parameters/reservedparameter.py +6 -2
- odxtools/parameters/systemparameter.py +55 -11
- odxtools/parameters/tableentryparameter.py +3 -2
- odxtools/parameters/tablekeyparameter.py +103 -49
- odxtools/parameters/tablestructparameter.py +47 -48
- odxtools/parameters/valueparameter.py +16 -20
- odxtools/paramlengthinfotype.py +52 -32
- odxtools/parentref.py +16 -2
- 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 +3 -3
- 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 +7 -17
- odxtools/staticfield.py +31 -25
- odxtools/subcomponent.py +288 -0
- odxtools/swvariable.py +21 -0
- odxtools/table.py +7 -8
- odxtools/tablerow.py +19 -11
- 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 -133
- 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 +4 -3
- odxtools/templates/macros/printOdxCategory.xml.jinja2 +28 -0
- odxtools/templates/macros/printParam.xml.jinja2 +11 -12
- 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 +1 -1
- 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} +20 -10
- odxtools/xdoc.py +3 -5
- {odxtools-6.7.0.dist-info → odxtools-9.3.0.dist-info}/METADATA +20 -21
- odxtools-9.3.0.dist-info/RECORD +228 -0
- {odxtools-6.7.0.dist-info → odxtools-9.3.0.dist-info}/WHEEL +1 -1
- odxtools/createcompanydatas.py +0 -17
- odxtools/createsdgs.py +0 -19
- 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 -216
- odxtools-6.7.0.dist-info/RECORD +0 -182
- /odxtools/{diaglayertype.py → diaglayers/diaglayertype.py} +0 -0
- {odxtools-6.7.0.dist-info → odxtools-9.3.0.dist-info}/LICENSE +0 -0
- {odxtools-6.7.0.dist-info → odxtools-9.3.0.dist-info}/entry_points.txt +0 -0
- {odxtools-6.7.0.dist-info → odxtools-9.3.0.dist-info}/top_level.txt +0 -0
odxtools/dataobjectproperty.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional, cast
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .compumethods.compumethod import CompuMethod
|
@@ -10,17 +10,15 @@ from .decodestate import DecodeState
|
|
10
10
|
from .diagcodedtype import DiagCodedType
|
11
11
|
from .dopbase import DopBase
|
12
12
|
from .encodestate import EncodeState
|
13
|
-
from .exceptions import DecodeError, EncodeError,
|
13
|
+
from .exceptions import DecodeError, EncodeError, odxraise, odxrequire
|
14
14
|
from .internalconstr import InternalConstr
|
15
15
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
16
16
|
from .odxtypes import AtomicOdxType, ParameterValue
|
17
17
|
from .physicaltype import PhysicalType
|
18
|
+
from .snrefcontext import SnRefContext
|
18
19
|
from .unit import Unit
|
19
20
|
from .utils import dataclass_fields_asdict
|
20
21
|
|
21
|
-
if TYPE_CHECKING:
|
22
|
-
from .diaglayer import DiagLayer
|
23
|
-
|
24
22
|
|
25
23
|
@dataclass
|
26
24
|
class DataObjectProperty(DopBase):
|
@@ -86,6 +84,7 @@ class DataObjectProperty(DopBase):
|
|
86
84
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
87
85
|
result = super()._build_odxlinks()
|
88
86
|
result.update(self.diag_coded_type._build_odxlinks())
|
87
|
+
result.update(self.compu_method._build_odxlinks())
|
89
88
|
return result
|
90
89
|
|
91
90
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
@@ -93,15 +92,17 @@ class DataObjectProperty(DopBase):
|
|
93
92
|
super()._resolve_odxlinks(odxlinks)
|
94
93
|
|
95
94
|
self.diag_coded_type._resolve_odxlinks(odxlinks)
|
95
|
+
self.compu_method._resolve_odxlinks(odxlinks)
|
96
96
|
|
97
97
|
self._unit: Optional[Unit] = None
|
98
98
|
if self.unit_ref:
|
99
99
|
self._unit = odxlinks.resolve(self.unit_ref, Unit)
|
100
100
|
|
101
|
-
def _resolve_snrefs(self,
|
102
|
-
super()._resolve_snrefs(
|
101
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
102
|
+
super()._resolve_snrefs(context)
|
103
103
|
|
104
|
-
self.diag_coded_type._resolve_snrefs(
|
104
|
+
self.diag_coded_type._resolve_snrefs(context)
|
105
|
+
self.compu_method._resolve_snrefs(context)
|
105
106
|
|
106
107
|
@property
|
107
108
|
def unit(self) -> Optional[Unit]:
|
@@ -110,20 +111,7 @@ class DataObjectProperty(DopBase):
|
|
110
111
|
def get_static_bit_length(self) -> Optional[int]:
|
111
112
|
return self.diag_coded_type.get_static_bit_length()
|
112
113
|
|
113
|
-
def
|
114
|
-
"""
|
115
|
-
Convert a physical representation of a parameter to its internal counterpart
|
116
|
-
"""
|
117
|
-
odxassert(
|
118
|
-
self.physical_type.base_data_type.isinstance(physical_value),
|
119
|
-
f"Expected {self.physical_type.base_data_type.value}, got {type(physical_value)}")
|
120
|
-
|
121
|
-
return self.compu_method.convert_physical_to_internal(physical_value)
|
122
|
-
|
123
|
-
def convert_physical_to_bytes(self,
|
124
|
-
physical_value: Any,
|
125
|
-
encode_state: EncodeState,
|
126
|
-
bit_position: int = 0) -> bytes:
|
114
|
+
def encode_into_pdu(self, physical_value: ParameterValue, encode_state: EncodeState) -> None:
|
127
115
|
"""
|
128
116
|
Convert a physical representation of a parameter to a string bytes that can be send over the wire
|
129
117
|
"""
|
@@ -132,9 +120,11 @@ class DataObjectProperty(DopBase):
|
|
132
120
|
f"The value {repr(physical_value)} of type {type(physical_value).__name__}"
|
133
121
|
f" is not a valid.")
|
134
122
|
|
135
|
-
|
136
|
-
|
137
|
-
|
123
|
+
if not isinstance(physical_value, (int, float, str, bytes, bytearray)):
|
124
|
+
odxraise(f"Invalid type '{type(physical_value).__name__}' for physical value. "
|
125
|
+
f"(Expect atomic type!)")
|
126
|
+
internal_value = self.compu_method.convert_physical_to_internal(physical_value)
|
127
|
+
self.diag_coded_type.encode_into_pdu(internal_value, encode_state)
|
138
128
|
|
139
129
|
def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
140
130
|
"""
|
odxtools/decodestate.py
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass, field
|
3
|
-
from typing import TYPE_CHECKING, Dict, cast
|
3
|
+
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, cast
|
4
4
|
|
5
5
|
import odxtools.exceptions as exceptions
|
6
6
|
|
7
7
|
from .exceptions import DecodeError
|
8
|
-
from .odxtypes import AtomicOdxType, DataType
|
8
|
+
from .odxtypes import AtomicOdxType, DataType, ParameterValue
|
9
9
|
|
10
10
|
try:
|
11
11
|
import bitstruct.c as bitstruct
|
@@ -13,20 +13,9 @@ except ImportError:
|
|
13
13
|
import bitstruct
|
14
14
|
|
15
15
|
if TYPE_CHECKING:
|
16
|
+
from .parameters.parameter import Parameter
|
16
17
|
from .tablerow import TableRow
|
17
18
|
|
18
|
-
# format specifiers for the data type using the bitstruct module
|
19
|
-
ODX_TYPE_TO_FORMAT_LETTER = {
|
20
|
-
DataType.A_INT32: "s",
|
21
|
-
DataType.A_UINT32: "u",
|
22
|
-
DataType.A_FLOAT32: "f",
|
23
|
-
DataType.A_FLOAT64: "f",
|
24
|
-
DataType.A_BYTEFIELD: "r",
|
25
|
-
DataType.A_UNICODE2STRING: "r", # UTF-16 strings must be converted explicitly
|
26
|
-
DataType.A_ASCIISTRING: "r",
|
27
|
-
DataType.A_UTF8STRING: "r",
|
28
|
-
}
|
29
|
-
|
30
19
|
|
31
20
|
@dataclass
|
32
21
|
class DecodeState:
|
@@ -58,6 +47,11 @@ class DecodeState:
|
|
58
47
|
#: values of the table key parameters decoded so far
|
59
48
|
table_keys: Dict[str, "TableRow"] = field(default_factory=dict)
|
60
49
|
|
50
|
+
#: List of parameters that have been decoded so far. The journal
|
51
|
+
#: is used by some types of parameters which depend on the values of
|
52
|
+
#: other parameters; i.e., environment data description parameters
|
53
|
+
journal: List[Tuple["Parameter", Optional[ParameterValue]]] = field(default_factory=list)
|
54
|
+
|
61
55
|
def extract_atomic_value(
|
62
56
|
self,
|
63
57
|
bit_length: int,
|
@@ -94,7 +88,7 @@ class DecodeState:
|
|
94
88
|
|
95
89
|
padding = (8 - (bit_length + self.cursor_bit_position) % 8) % 8
|
96
90
|
internal_value, = bitstruct.unpack_from(
|
97
|
-
f"{
|
91
|
+
f"{base_data_type.bitstruct_format_letter}{bit_length}",
|
98
92
|
extracted_bytes,
|
99
93
|
offset=padding)
|
100
94
|
|
odxtools/description.py
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import List, Optional
|
3
|
+
from xml.etree import ElementTree
|
4
|
+
|
5
|
+
from .exceptions import odxrequire
|
6
|
+
from .odxlink import OdxDocFragment
|
7
|
+
|
8
|
+
|
9
|
+
@dataclass
|
10
|
+
class Description:
|
11
|
+
text: str
|
12
|
+
external_docs: List[str]
|
13
|
+
text_identifier: Optional[str]
|
14
|
+
|
15
|
+
@staticmethod
|
16
|
+
def from_et(et_element: Optional[ElementTree.Element],
|
17
|
+
doc_frags: List[OdxDocFragment]) -> Optional["Description"]:
|
18
|
+
if et_element is None:
|
19
|
+
return None
|
20
|
+
|
21
|
+
# Extract the contents of the tag as a XHTML string.
|
22
|
+
raw_string = et_element.text or ""
|
23
|
+
for e in et_element:
|
24
|
+
if e.tag == "EXTERNAL-DOCS":
|
25
|
+
break
|
26
|
+
raw_string += ElementTree.tostring(e, encoding="unicode")
|
27
|
+
|
28
|
+
# remove white spaces at the beginning and at the end of all
|
29
|
+
# extracted lines
|
30
|
+
stripped_lines = [x.strip() for x in raw_string.split("\n")]
|
31
|
+
|
32
|
+
text = "\n".join(stripped_lines).strip()
|
33
|
+
|
34
|
+
text_identifier = et_element.get("TI")
|
35
|
+
|
36
|
+
external_docs = \
|
37
|
+
[
|
38
|
+
odxrequire(ed.get("HREF")) for ed in et_element.iterfind("EXTERNAL-DOCS/EXTERNAL-DOC")
|
39
|
+
]
|
40
|
+
return Description(text=text, text_identifier=text_identifier, external_docs=external_docs)
|
41
|
+
|
42
|
+
@staticmethod
|
43
|
+
def from_string(text: str) -> "Description":
|
44
|
+
return Description(text=text, external_docs=[], text_identifier=None)
|
45
|
+
|
46
|
+
def __str__(self) -> str:
|
47
|
+
return self.text
|
@@ -1,13 +1,12 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
1
2
|
from dataclasses import dataclass
|
2
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional
|
3
4
|
from xml.etree import ElementTree
|
4
5
|
|
5
6
|
from .dataobjectproperty import DataObjectProperty
|
6
7
|
from .exceptions import odxrequire
|
7
8
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
8
|
-
|
9
|
-
if TYPE_CHECKING:
|
10
|
-
from .diaglayer import DiagLayer
|
9
|
+
from .snrefcontext import SnRefContext
|
11
10
|
|
12
11
|
|
13
12
|
@dataclass
|
@@ -39,7 +38,7 @@ class DetermineNumberOfItems:
|
|
39
38
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
40
39
|
self._dop = odxlinks.resolve(self.dop_ref, DataObjectProperty)
|
41
40
|
|
42
|
-
def _resolve_snrefs(self,
|
41
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
43
42
|
pass
|
44
43
|
|
45
44
|
@property
|
odxtools/diagcodedtype.py
CHANGED
@@ -1,21 +1,14 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
-
import abc
|
3
2
|
from dataclasses import dataclass
|
4
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Literal, Optional, Union, cast
|
4
|
+
from xml.etree import ElementTree
|
5
5
|
|
6
|
-
from .decodestate import
|
6
|
+
from .decodestate import DecodeState
|
7
7
|
from .encodestate import EncodeState
|
8
|
-
from .exceptions import
|
9
|
-
from .odxlink import OdxLinkDatabase, OdxLinkId
|
10
|
-
from .odxtypes import AtomicOdxType, DataType
|
11
|
-
|
12
|
-
try:
|
13
|
-
import bitstruct.c as bitstruct
|
14
|
-
except ImportError:
|
15
|
-
import bitstruct
|
16
|
-
|
17
|
-
if TYPE_CHECKING:
|
18
|
-
from .diaglayer import DiagLayer
|
8
|
+
from .exceptions import odxassert, odxraise, odxrequire
|
9
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
10
|
+
from .odxtypes import AtomicOdxType, DataType, odxstr_to_bool
|
11
|
+
from .snrefcontext import SnRefContext
|
19
12
|
|
20
13
|
# Allowed diag-coded types
|
21
14
|
DctType = Literal[
|
@@ -27,12 +20,30 @@ DctType = Literal[
|
|
27
20
|
|
28
21
|
|
29
22
|
@dataclass
|
30
|
-
class DiagCodedType
|
23
|
+
class DiagCodedType:
|
31
24
|
|
32
25
|
base_data_type: DataType
|
33
26
|
base_type_encoding: Optional[str]
|
34
27
|
is_highlow_byte_order_raw: Optional[bool]
|
35
28
|
|
29
|
+
@staticmethod
|
30
|
+
def from_et(et_element: ElementTree.Element,
|
31
|
+
doc_frags: List[OdxDocFragment]) -> "DiagCodedType":
|
32
|
+
base_data_type_str = odxrequire(et_element.get("BASE-DATA-TYPE"))
|
33
|
+
try:
|
34
|
+
base_data_type = DataType(base_data_type_str)
|
35
|
+
except ValueError:
|
36
|
+
odxraise(f"Unknown base data type {base_data_type_str}")
|
37
|
+
base_data_type = cast(DataType, None)
|
38
|
+
|
39
|
+
base_type_encoding = et_element.get("BASE-TYPE-ENCODING")
|
40
|
+
is_highlow_byte_order_raw = odxstr_to_bool(et_element.get("IS-HIGHLOW-BYTE-ORDER"))
|
41
|
+
|
42
|
+
return DiagCodedType(
|
43
|
+
base_data_type=base_data_type,
|
44
|
+
base_type_encoding=base_type_encoding,
|
45
|
+
is_highlow_byte_order_raw=is_highlow_byte_order_raw)
|
46
|
+
|
36
47
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]: # noqa: B027
|
37
48
|
return {}
|
38
49
|
|
@@ -40,7 +51,7 @@ class DiagCodedType(abc.ABC):
|
|
40
51
|
"""Recursively resolve any odxlinks references"""
|
41
52
|
pass
|
42
53
|
|
43
|
-
def _resolve_snrefs(self,
|
54
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None: # noqa: B027
|
44
55
|
"""Recursively resolve any short-name references"""
|
45
56
|
pass
|
46
57
|
|
@@ -48,96 +59,15 @@ class DiagCodedType(abc.ABC):
|
|
48
59
|
return None
|
49
60
|
|
50
61
|
@property
|
51
|
-
@abc.abstractmethod
|
52
62
|
def dct_type(self) -> DctType:
|
53
|
-
|
63
|
+
odxraise(f"Class {type(self).__name__} does not override required method "
|
64
|
+
f"dct_type()", NotImplementedError)
|
65
|
+
return cast(DctType, None)
|
54
66
|
|
55
67
|
@property
|
56
68
|
def is_highlow_byte_order(self) -> bool:
|
57
69
|
return self.is_highlow_byte_order_raw in [None, True]
|
58
70
|
|
59
|
-
@staticmethod
|
60
|
-
def _encode_internal_value(
|
61
|
-
internal_value: AtomicOdxType,
|
62
|
-
bit_position: int,
|
63
|
-
bit_length: int,
|
64
|
-
base_data_type: DataType,
|
65
|
-
is_highlow_byte_order: bool,
|
66
|
-
) -> bytes:
|
67
|
-
"""Convert the internal_value to bytes."""
|
68
|
-
# Check that bytes and strings actually fit into the bit length
|
69
|
-
if base_data_type == DataType.A_BYTEFIELD:
|
70
|
-
if isinstance(internal_value, bytearray):
|
71
|
-
internal_value = bytes(internal_value)
|
72
|
-
if not isinstance(internal_value, bytes):
|
73
|
-
odxraise()
|
74
|
-
if 8 * len(internal_value) > bit_length:
|
75
|
-
raise EncodeError(f"The bytefield {internal_value.hex()} is too large "
|
76
|
-
f"({len(internal_value)} bytes)."
|
77
|
-
f" The maximum length is {bit_length//8}.")
|
78
|
-
if base_data_type == DataType.A_ASCIISTRING:
|
79
|
-
if not isinstance(internal_value, str):
|
80
|
-
odxraise()
|
81
|
-
|
82
|
-
# The spec says ASCII, meaning only byte values 0-127.
|
83
|
-
# But in practice, vendors use iso-8859-1, aka latin-1
|
84
|
-
# reason being iso-8859-1 never fails since it has a valid
|
85
|
-
# character mapping for every possible byte sequence.
|
86
|
-
internal_value = internal_value.encode("iso-8859-1")
|
87
|
-
|
88
|
-
if 8 * len(internal_value) > bit_length:
|
89
|
-
raise EncodeError(f"The string {repr(internal_value)} is too large."
|
90
|
-
f" The maximum number of characters is {bit_length//8}.")
|
91
|
-
elif base_data_type == DataType.A_UTF8STRING:
|
92
|
-
if not isinstance(internal_value, str):
|
93
|
-
odxraise()
|
94
|
-
|
95
|
-
internal_value = internal_value.encode("utf-8")
|
96
|
-
|
97
|
-
if 8 * len(internal_value) > bit_length:
|
98
|
-
raise EncodeError(f"The string {repr(internal_value)} is too large."
|
99
|
-
f" The maximum number of bytes is {bit_length//8}.")
|
100
|
-
|
101
|
-
elif base_data_type == DataType.A_UNICODE2STRING:
|
102
|
-
if not isinstance(internal_value, str):
|
103
|
-
odxraise()
|
104
|
-
|
105
|
-
text_encoding = "utf-16-be" if is_highlow_byte_order else "utf-16-le"
|
106
|
-
internal_value = internal_value.encode(text_encoding)
|
107
|
-
|
108
|
-
if 8 * len(internal_value) > bit_length:
|
109
|
-
raise EncodeError(f"The string {repr(internal_value)} is too large."
|
110
|
-
f" The maximum number of characters is {bit_length//16}.")
|
111
|
-
|
112
|
-
# If the bit length is zero, return empty bytes
|
113
|
-
if bit_length == 0:
|
114
|
-
if (base_data_type.value in [
|
115
|
-
DataType.A_INT32, DataType.A_UINT32, DataType.A_FLOAT32, DataType.A_FLOAT64
|
116
|
-
] and base_data_type.value != 0):
|
117
|
-
raise EncodeError(
|
118
|
-
f"The number {repr(internal_value)} cannot be encoded into {bit_length} bits.")
|
119
|
-
return b''
|
120
|
-
|
121
|
-
char = ODX_TYPE_TO_FORMAT_LETTER[base_data_type]
|
122
|
-
padding = (8 - ((bit_length + bit_position) % 8)) % 8
|
123
|
-
odxassert((0 <= padding and padding < 8 and (padding + bit_length + bit_position) % 8 == 0),
|
124
|
-
f"Incorrect padding {padding}")
|
125
|
-
left_pad = f"p{padding}" if padding > 0 else ""
|
126
|
-
|
127
|
-
# actually encode the value
|
128
|
-
coded = bitstruct.pack(f"{left_pad}{char}{bit_length}", internal_value)
|
129
|
-
|
130
|
-
# apply byte order for numeric objects
|
131
|
-
if not is_highlow_byte_order and base_data_type in [
|
132
|
-
DataType.A_INT32,
|
133
|
-
DataType.A_UINT32,
|
134
|
-
DataType.A_FLOAT32,
|
135
|
-
DataType.A_FLOAT64,
|
136
|
-
]:
|
137
|
-
coded = coded[::-1]
|
138
|
-
|
139
|
-
return cast(bytes, coded)
|
140
|
-
|
141
71
|
def _minimal_byte_length_of(self, internal_value: Union[bytes, str]) -> int:
|
142
72
|
"""Helper method to get the minimal byte length.
|
143
73
|
(needed for LeadingLength- and MinMaxLengthType)
|
@@ -160,11 +90,10 @@ class DiagCodedType(abc.ABC):
|
|
160
90
|
odxassert(
|
161
91
|
byte_length % 2 == 0, f"The bit length of A_UNICODE2STRING must"
|
162
92
|
f" be a multiple of 16 but is {8*byte_length}")
|
93
|
+
|
163
94
|
return byte_length
|
164
95
|
|
165
|
-
|
166
|
-
def convert_internal_to_bytes(self, internal_value: AtomicOdxType, encode_state: EncodeState,
|
167
|
-
bit_position: int) -> bytes:
|
96
|
+
def encode_into_pdu(self, internal_value: AtomicOdxType, encode_state: EncodeState) -> None:
|
168
97
|
"""Encode the internal value.
|
169
98
|
|
170
99
|
Parameters
|
@@ -177,9 +106,9 @@ class DiagCodedType(abc.ABC):
|
|
177
106
|
mapping from ID (of the length key) to bit length
|
178
107
|
(only needed for ParamLengthInfoType)
|
179
108
|
"""
|
180
|
-
|
109
|
+
raise NotImplementedError(
|
110
|
+
f".encode_into_pdu() is not implemented by the class {type(self).__name__}")
|
181
111
|
|
182
|
-
@abc.abstractmethod
|
183
112
|
def decode_from_pdu(self, decode_state: DecodeState) -> AtomicOdxType:
|
184
113
|
"""Decode the parameter value from the coded message.
|
185
114
|
|
@@ -195,4 +124,5 @@ class DiagCodedType(abc.ABC):
|
|
195
124
|
int
|
196
125
|
the next byte position after the extracted parameter
|
197
126
|
"""
|
198
|
-
|
127
|
+
raise NotImplementedError(
|
128
|
+
f".decode_from_pdu() is not implemented by the class {type(self).__name__}")
|
odxtools/diagcomm.py
CHANGED
@@ -6,20 +6,20 @@ from xml.etree import ElementTree
|
|
6
6
|
|
7
7
|
from .admindata import AdminData
|
8
8
|
from .audience import Audience
|
9
|
-
from .createsdgs import create_sdgs_from_et
|
10
9
|
from .element import IdentifiableElement
|
11
10
|
from .exceptions import odxraise, odxrequire
|
12
11
|
from .functionalclass import FunctionalClass
|
13
12
|
from .nameditemlist import NamedItemList
|
14
|
-
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
13
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
15
14
|
from .odxtypes import odxstr_to_bool
|
15
|
+
from .snrefcontext import SnRefContext
|
16
16
|
from .specialdatagroup import SpecialDataGroup
|
17
17
|
from .state import State
|
18
18
|
from .statetransition import StateTransition
|
19
19
|
from .utils import dataclass_fields_asdict
|
20
20
|
|
21
21
|
if TYPE_CHECKING:
|
22
|
-
from .
|
22
|
+
from .diaglayers.protocol import Protocol
|
23
23
|
|
24
24
|
|
25
25
|
class DiagClassType(Enum):
|
@@ -76,7 +76,9 @@ class DiagComm(IdentifiableElement):
|
|
76
76
|
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
77
77
|
|
78
78
|
admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
|
79
|
-
sdgs =
|
79
|
+
sdgs = [
|
80
|
+
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
81
|
+
]
|
80
82
|
|
81
83
|
functional_class_refs = [
|
82
84
|
odxrequire(OdxLinkRef.from_et(el, doc_frags))
|
@@ -141,7 +143,7 @@ class DiagComm(IdentifiableElement):
|
|
141
143
|
return self._functional_classes
|
142
144
|
|
143
145
|
@property
|
144
|
-
def protocols(self) -> NamedItemList["
|
146
|
+
def protocols(self) -> NamedItemList["Protocol"]:
|
145
147
|
return self._protocols
|
146
148
|
|
147
149
|
@property
|
@@ -201,15 +203,25 @@ class DiagComm(IdentifiableElement):
|
|
201
203
|
self._state_transitions = NamedItemList(
|
202
204
|
[odxlinks.resolve(stt_ref, StateTransition) for stt_ref in self.state_transition_refs])
|
203
205
|
|
204
|
-
def _resolve_snrefs(self,
|
206
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
205
207
|
if self.admin_data:
|
206
|
-
self.admin_data._resolve_snrefs(
|
208
|
+
self.admin_data._resolve_snrefs(context)
|
207
209
|
|
208
210
|
if self.audience:
|
209
|
-
self.audience._resolve_snrefs(
|
211
|
+
self.audience._resolve_snrefs(context)
|
210
212
|
|
211
213
|
for sdg in self.sdgs:
|
212
|
-
sdg._resolve_snrefs(
|
213
|
-
|
214
|
-
|
215
|
-
|
214
|
+
sdg._resolve_snrefs(context)
|
215
|
+
|
216
|
+
if TYPE_CHECKING:
|
217
|
+
diag_layer = odxrequire(context.diag_layer)
|
218
|
+
self._protocols = NamedItemList([
|
219
|
+
resolve_snref(prot_snref, getattr(diag_layer, "protocols", []), Protocol)
|
220
|
+
for prot_snref in self.protocol_snrefs
|
221
|
+
])
|
222
|
+
else:
|
223
|
+
diag_layer = odxrequire(context.diag_layer)
|
224
|
+
self._protocols = NamedItemList([
|
225
|
+
resolve_snref(prot_snref, getattr(diag_layer, "protocols", []))
|
226
|
+
for prot_snref in self.protocol_snrefs
|
227
|
+
])
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from itertools import chain
|
4
|
-
from typing import
|
4
|
+
from typing import Any, Dict, List, Optional
|
5
5
|
from xml.etree import ElementTree
|
6
6
|
|
7
7
|
from .admindata import AdminData
|
8
8
|
from .basicstructure import BasicStructure
|
9
|
-
from .createsdgs import create_sdgs_from_et
|
10
9
|
from .dataobjectproperty import DataObjectProperty
|
11
10
|
from .dopbase import DopBase
|
12
11
|
from .dtcdop import DtcDop
|
12
|
+
from .dynamicendmarkerfield import DynamicEndmarkerField
|
13
13
|
from .dynamiclengthfield import DynamicLengthField
|
14
14
|
from .endofpdufield import EndOfPduField
|
15
15
|
from .environmentdata import EnvironmentData
|
@@ -18,15 +18,13 @@ from .exceptions import odxraise
|
|
18
18
|
from .multiplexer import Multiplexer
|
19
19
|
from .nameditemlist import NamedItemList
|
20
20
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
21
|
+
from .snrefcontext import SnRefContext
|
21
22
|
from .specialdatagroup import SpecialDataGroup
|
22
23
|
from .staticfield import StaticField
|
23
24
|
from .structure import Structure
|
24
25
|
from .table import Table
|
25
26
|
from .unitspec import UnitSpec
|
26
27
|
|
27
|
-
if TYPE_CHECKING:
|
28
|
-
from .diaglayer import DiagLayer
|
29
|
-
|
30
28
|
|
31
29
|
@dataclass
|
32
30
|
class DiagDataDictionarySpec:
|
@@ -37,7 +35,7 @@ class DiagDataDictionarySpec:
|
|
37
35
|
structures: NamedItemList[BasicStructure]
|
38
36
|
static_fields: NamedItemList[StaticField]
|
39
37
|
dynamic_length_fields: NamedItemList[DynamicLengthField]
|
40
|
-
|
38
|
+
dynamic_endmarker_fields: NamedItemList[DynamicEndmarkerField]
|
41
39
|
end_of_pdu_fields: NamedItemList[EndOfPduField]
|
42
40
|
muxs: NamedItemList[Multiplexer]
|
43
41
|
env_datas: NamedItemList[EnvironmentData]
|
@@ -54,7 +52,7 @@ class DiagDataDictionarySpec:
|
|
54
52
|
self.structures,
|
55
53
|
self.static_fields,
|
56
54
|
self.dynamic_length_fields,
|
57
|
-
|
55
|
+
self.dynamic_endmarker_fields,
|
58
56
|
self.end_of_pdu_fields,
|
59
57
|
self.muxs,
|
60
58
|
self.env_datas,
|
@@ -99,11 +97,10 @@ class DiagDataDictionarySpec:
|
|
99
97
|
for dl_element in et_element.iterfind("DYNAMIC-LENGTH-FIELDS/DYNAMIC-LENGTH-FIELD")
|
100
98
|
]
|
101
99
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
#]
|
100
|
+
dynamic_endmarker_fields = [
|
101
|
+
DynamicEndmarkerField.from_et(dl_element, doc_frags) for dl_element in
|
102
|
+
et_element.iterfind("DYNAMIC-ENDMARKER-FIELDS/DYNAMIC-ENDMARKER-FIELD")
|
103
|
+
]
|
107
104
|
|
108
105
|
end_of_pdu_fields = [
|
109
106
|
EndOfPduField.from_et(eofp_element, doc_frags)
|
@@ -135,7 +132,9 @@ class DiagDataDictionarySpec:
|
|
135
132
|
for table_element in et_element.iterfind("TABLES/TABLE")
|
136
133
|
]
|
137
134
|
|
138
|
-
sdgs =
|
135
|
+
sdgs = [
|
136
|
+
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
137
|
+
]
|
139
138
|
|
140
139
|
return DiagDataDictionarySpec(
|
141
140
|
admin_data=admin_data,
|
@@ -145,7 +144,7 @@ class DiagDataDictionarySpec:
|
|
145
144
|
structures=NamedItemList(structures),
|
146
145
|
static_fields=NamedItemList(static_fields),
|
147
146
|
dynamic_length_fields=NamedItemList(dynamic_length_fields),
|
148
|
-
|
147
|
+
dynamic_endmarker_fields=NamedItemList(dynamic_endmarker_fields),
|
149
148
|
end_of_pdu_fields=NamedItemList(end_of_pdu_fields),
|
150
149
|
muxs=NamedItemList(muxs),
|
151
150
|
env_datas=NamedItemList(env_datas),
|
@@ -172,8 +171,8 @@ class DiagDataDictionarySpec:
|
|
172
171
|
odxlinks.update(static_field._build_odxlinks())
|
173
172
|
for dynamic_length_field in self.dynamic_length_fields:
|
174
173
|
odxlinks.update(dynamic_length_field._build_odxlinks())
|
175
|
-
|
176
|
-
|
174
|
+
for dynamic_endmarker_field in self.dynamic_endmarker_fields:
|
175
|
+
odxlinks.update(dynamic_endmarker_field._build_odxlinks())
|
177
176
|
for end_of_pdu_field in self.end_of_pdu_fields:
|
178
177
|
odxlinks.update(end_of_pdu_field._build_odxlinks())
|
179
178
|
for mux in self.muxs:
|
@@ -204,8 +203,8 @@ class DiagDataDictionarySpec:
|
|
204
203
|
static_field._resolve_odxlinks(odxlinks)
|
205
204
|
for dynamic_length_field in self.dynamic_length_fields:
|
206
205
|
dynamic_length_field._resolve_odxlinks(odxlinks)
|
207
|
-
|
208
|
-
|
206
|
+
for dynamic_endmarker_field in self.dynamic_endmarker_fields:
|
207
|
+
dynamic_endmarker_field._resolve_odxlinks(odxlinks)
|
209
208
|
for end_of_pdu_field in self.end_of_pdu_fields:
|
210
209
|
end_of_pdu_field._resolve_odxlinks(odxlinks)
|
211
210
|
for mux in self.muxs:
|
@@ -219,35 +218,35 @@ class DiagDataDictionarySpec:
|
|
219
218
|
for sdg in self.sdgs:
|
220
219
|
sdg._resolve_odxlinks(odxlinks)
|
221
220
|
|
222
|
-
def _resolve_snrefs(self,
|
221
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
223
222
|
if self.admin_data is not None:
|
224
|
-
self.admin_data._resolve_snrefs(
|
223
|
+
self.admin_data._resolve_snrefs(context)
|
225
224
|
for dtc_dop in self.dtc_dops:
|
226
|
-
dtc_dop._resolve_snrefs(
|
225
|
+
dtc_dop._resolve_snrefs(context)
|
227
226
|
for env_data_desc in self.env_data_descs:
|
228
|
-
env_data_desc._resolve_snrefs(
|
227
|
+
env_data_desc._resolve_snrefs(context)
|
229
228
|
for data_object_prop in self.data_object_props:
|
230
|
-
data_object_prop._resolve_snrefs(
|
229
|
+
data_object_prop._resolve_snrefs(context)
|
231
230
|
for structure in self.structures:
|
232
|
-
structure._resolve_snrefs(
|
231
|
+
structure._resolve_snrefs(context)
|
233
232
|
for static_field in self.static_fields:
|
234
|
-
static_field._resolve_snrefs(
|
233
|
+
static_field._resolve_snrefs(context)
|
235
234
|
for dynamic_length_field in self.dynamic_length_fields:
|
236
|
-
dynamic_length_field._resolve_snrefs(
|
237
|
-
|
238
|
-
|
235
|
+
dynamic_length_field._resolve_snrefs(context)
|
236
|
+
for dynamic_endmarker_field in self.dynamic_endmarker_fields:
|
237
|
+
dynamic_endmarker_field._resolve_snrefs(context)
|
239
238
|
for end_of_pdu_field in self.end_of_pdu_fields:
|
240
|
-
end_of_pdu_field._resolve_snrefs(
|
239
|
+
end_of_pdu_field._resolve_snrefs(context)
|
241
240
|
for mux in self.muxs:
|
242
|
-
mux._resolve_snrefs(
|
241
|
+
mux._resolve_snrefs(context)
|
243
242
|
for env_data in self.env_datas:
|
244
|
-
env_data._resolve_snrefs(
|
243
|
+
env_data._resolve_snrefs(context)
|
245
244
|
if self.unit_spec is not None:
|
246
|
-
self.unit_spec._resolve_snrefs(
|
245
|
+
self.unit_spec._resolve_snrefs(context)
|
247
246
|
for table in self.tables:
|
248
|
-
table._resolve_snrefs(
|
247
|
+
table._resolve_snrefs(context)
|
249
248
|
for sdg in self.sdgs:
|
250
|
-
sdg._resolve_snrefs(
|
249
|
+
sdg._resolve_snrefs(context)
|
251
250
|
|
252
251
|
@property
|
253
252
|
def all_data_object_properties(self) -> NamedItemList[DopBase]:
|