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
@@ -3,18 +3,18 @@ from dataclasses import dataclass
|
|
3
3
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
-
from typing_extensions import override
|
6
|
+
from typing_extensions import final, override
|
7
7
|
|
8
8
|
from ..decodestate import DecodeState
|
9
9
|
from ..encodestate import EncodeState
|
10
10
|
from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
|
11
|
-
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
11
|
+
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
12
12
|
from ..odxtypes import ParameterValue
|
13
|
+
from ..snrefcontext import SnRefContext
|
13
14
|
from ..utils import dataclass_fields_asdict
|
14
15
|
from .parameter import Parameter, ParameterType
|
15
16
|
|
16
17
|
if TYPE_CHECKING:
|
17
|
-
from ..diaglayer import DiagLayer
|
18
18
|
from ..table import Table
|
19
19
|
from ..tablerow import TableRow
|
20
20
|
|
@@ -56,8 +56,8 @@ class TableKeyParameter(Parameter):
|
|
56
56
|
**kwargs)
|
57
57
|
|
58
58
|
def __post_init__(self) -> None:
|
59
|
-
self._table:
|
60
|
-
self._table_row: Optional[
|
59
|
+
self._table: Table
|
60
|
+
self._table_row: Optional[TableRow] = None
|
61
61
|
if self.table_ref is None and self.table_snref is None and \
|
62
62
|
self.table_row_ref is None and self.table_row_snref is None:
|
63
63
|
odxraise("Either a table or a table row must be defined.")
|
@@ -80,41 +80,48 @@ class TableKeyParameter(Parameter):
|
|
80
80
|
super()._resolve_odxlinks(odxlinks)
|
81
81
|
|
82
82
|
# Either table_ref or table_row_ref will be defined
|
83
|
-
if self.table_ref:
|
83
|
+
if self.table_ref is not None:
|
84
84
|
if TYPE_CHECKING:
|
85
85
|
self._table = odxlinks.resolve(self.table_ref, Table)
|
86
86
|
else:
|
87
87
|
self._table = odxlinks.resolve(self.table_ref)
|
88
88
|
|
89
|
-
if self.table_row_ref:
|
89
|
+
if self.table_row_ref is not None:
|
90
90
|
if TYPE_CHECKING:
|
91
91
|
self._table_row = odxlinks.resolve(self.table_row_ref, TableRow)
|
92
92
|
else:
|
93
93
|
self._table_row = odxlinks.resolve(self.table_row_ref)
|
94
|
-
|
94
|
+
|
95
|
+
if self.table_ref is None and self.table_snref is None:
|
96
|
+
if TYPE_CHECKING:
|
97
|
+
self._table = odxlinks.resolve(self._table_row.table_ref, Table)
|
98
|
+
else:
|
99
|
+
self._table = odxlinks.resolve(self._table_row.table_ref)
|
95
100
|
|
96
101
|
@override
|
97
|
-
def _resolve_snrefs(self,
|
98
|
-
super()._resolve_snrefs(
|
102
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
103
|
+
super()._resolve_snrefs(context)
|
99
104
|
|
100
105
|
if self.table_snref is not None:
|
101
|
-
|
102
|
-
|
106
|
+
tables = odxrequire(context.diag_layer).diag_data_dictionary_spec.tables
|
107
|
+
if TYPE_CHECKING:
|
108
|
+
self._table = resolve_snref(self.table_snref, tables, Table)
|
109
|
+
else:
|
110
|
+
self._table = resolve_snref(self.table_snref, tables)
|
103
111
|
if self.table_row_snref is not None:
|
104
112
|
# make sure that we know the table to which the table row
|
105
113
|
# SNREF is relative to.
|
106
114
|
table = odxrequire(
|
107
|
-
self._table, "If a table
|
108
|
-
"
|
109
|
-
|
115
|
+
self._table, "If a table row is referenced via short name, a table must "
|
116
|
+
"be referenced as well")
|
117
|
+
if TYPE_CHECKING:
|
118
|
+
self._table_row = resolve_snref(self.table_row_snref, table.table_rows, TableRow)
|
119
|
+
else:
|
120
|
+
self._table_row = resolve_snref(self.table_row_snref, table.table_rows)
|
110
121
|
|
111
122
|
@property
|
112
123
|
def table(self) -> "Table":
|
113
|
-
|
114
|
-
return self._table
|
115
|
-
if self._table_row is not None:
|
116
|
-
return self._table_row.table
|
117
|
-
odxraise(f'Could not resolve the table of {self.short_name}')
|
124
|
+
return self._table
|
118
125
|
|
119
126
|
@property
|
120
127
|
def table_row(self) -> Optional["TableRow"]:
|
@@ -133,46 +140,93 @@ class TableKeyParameter(Parameter):
|
|
133
140
|
return True
|
134
141
|
|
135
142
|
@override
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
if
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
143
|
+
@final
|
144
|
+
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
145
|
+
encode_state: EncodeState) -> None:
|
146
|
+
# if you get this exception, you ought to use
|
147
|
+
# `.encode_placeholder_into_pdu()` followed by (after the
|
148
|
+
# value of the table key has been determined)
|
149
|
+
# `.encode_value_into_pdu()`.
|
150
|
+
raise RuntimeError("_encode_positioned_into_pdu() cannot be called for table keys.")
|
151
|
+
|
152
|
+
def encode_placeholder_into_pdu(self, physical_value: Optional[ParameterValue],
|
153
|
+
encode_state: EncodeState) -> None:
|
154
|
+
|
155
|
+
if physical_value is not None:
|
144
156
|
key_dop = self.table.key_dop
|
145
157
|
if key_dop is None:
|
146
|
-
|
147
|
-
|
148
|
-
|
158
|
+
odxraise(
|
159
|
+
f"Table '{self.table.short_name}' does not define "
|
160
|
+
f"a KEY-DOP, but is used by TABLE-KEY parameter "
|
161
|
+
f"'{self.short_name}'", EncodeError)
|
162
|
+
return
|
163
|
+
|
164
|
+
if not isinstance(physical_value, str):
|
165
|
+
odxraise(f"Invalid type for for table key '{self.short_name}' specified. "
|
166
|
+
f"(expect name of table row.)")
|
167
|
+
|
168
|
+
tkv = encode_state.table_keys.get(self.short_name)
|
169
|
+
if tkv is not None and tkv != physical_value:
|
170
|
+
odxraise(f"Got conflicting values for table key {self.short_name}: "
|
171
|
+
f"{tkv} and {physical_value!r}")
|
172
|
+
|
173
|
+
encode_state.table_keys[self.short_name] = physical_value
|
174
|
+
|
175
|
+
pos = encode_state.cursor_byte_position
|
176
|
+
if self.byte_position is not None:
|
177
|
+
pos = encode_state.origin_byte_position + self.byte_position
|
178
|
+
encode_state.key_pos[self.short_name] = pos
|
179
|
+
encode_state.cursor_byte_position = pos
|
180
|
+
encode_state.cursor_bit_position = self.bit_position or 0
|
181
|
+
|
182
|
+
key_dop = self.table.key_dop
|
183
|
+
if key_dop is None:
|
184
|
+
odxraise(f"No KEY-DOP specified for table {self.table.short_name}")
|
185
|
+
return
|
186
|
+
|
187
|
+
sz = key_dop.get_static_bit_length()
|
188
|
+
if sz is None:
|
189
|
+
odxraise("The DOP of table key {self.short_name} must exhibit a fixed size.",
|
190
|
+
EncodeError)
|
191
|
+
return
|
149
192
|
|
150
|
-
|
151
|
-
|
152
|
-
|
193
|
+
# emplace a value of zero into the encode state, but pretend the bits not to be used
|
194
|
+
n = sz + encode_state.cursor_bit_position
|
195
|
+
tmp_val = b'\x00' * ((n + 7) // 8)
|
196
|
+
encode_state.emplace_bytes(tmp_val, obj_used_mask=tmp_val)
|
153
197
|
|
154
|
-
|
198
|
+
encode_state.cursor_bit_position = 0
|
155
199
|
|
156
|
-
|
157
|
-
|
200
|
+
def encode_value_into_pdu(self, encode_state: EncodeState) -> None:
|
201
|
+
|
202
|
+
key_dop = self.table.key_dop
|
203
|
+
if key_dop is None:
|
204
|
+
odxraise(
|
205
|
+
f"Table '{self.table.short_name}' does not define "
|
206
|
+
f"a KEY-DOP, but is used by TABLE-KEY parameter "
|
207
|
+
f"'{self.short_name}'", EncodeError)
|
208
|
+
return
|
209
|
+
|
210
|
+
if self.short_name not in encode_state.table_keys:
|
211
|
+
odxraise(f"Table key {self.short_name} has not been defined before "
|
212
|
+
f"it is required.", EncodeError)
|
213
|
+
return
|
214
|
+
else:
|
215
|
+
tr_short_name = encode_state.table_keys[self.short_name]
|
216
|
+
|
217
|
+
# We need to encode the table key using the associated DOP into the PDU.
|
158
218
|
tr_candidates = [x for x in self.table.table_rows if x.short_name == tr_short_name]
|
159
219
|
if len(tr_candidates) == 0:
|
160
|
-
|
220
|
+
odxraise(f"No table row with short name '{tr_short_name}' found", EncodeError)
|
221
|
+
return
|
161
222
|
elif len(tr_candidates) > 1:
|
162
|
-
|
223
|
+
odxraise(f"Multiple rows exhibiting short name '{tr_short_name}'", EncodeError)
|
163
224
|
tr = tr_candidates[0]
|
164
225
|
|
165
|
-
|
166
|
-
|
167
|
-
raise EncodeError(f"Table '{self.table.short_name}' does not define "
|
168
|
-
f"a KEY-DOP, but is used in TABLE-KEY parameter "
|
169
|
-
f"'{self.short_name}'")
|
170
|
-
bit_position = 0 if self.bit_position is None else self.bit_position
|
171
|
-
return key_dop.convert_physical_to_bytes(tr.key, encode_state, bit_position=bit_position)
|
226
|
+
encode_state.cursor_byte_position = encode_state.key_pos[self.short_name]
|
227
|
+
encode_state.cursor_bit_position = self.bit_position or 0
|
172
228
|
|
173
|
-
|
174
|
-
def encode_into_pdu(self, encode_state: EncodeState) -> bytes:
|
175
|
-
return super().encode_into_pdu(encode_state)
|
229
|
+
key_dop.encode_into_pdu(encode_state=encode_state, physical_value=odxrequire(tr.key))
|
176
230
|
|
177
231
|
@override
|
178
232
|
def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
@@ -1,23 +1,20 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
-
import warnings
|
3
2
|
from dataclasses import dataclass
|
4
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional, cast
|
5
4
|
from xml.etree import ElementTree
|
6
5
|
|
7
6
|
from typing_extensions import override
|
8
7
|
|
9
8
|
from ..decodestate import DecodeState
|
10
9
|
from ..encodestate import EncodeState
|
11
|
-
from ..exceptions import DecodeError, EncodeError,
|
12
|
-
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
10
|
+
from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
|
11
|
+
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
13
12
|
from ..odxtypes import ParameterValue
|
13
|
+
from ..snrefcontext import SnRefContext
|
14
14
|
from ..utils import dataclass_fields_asdict
|
15
15
|
from .parameter import Parameter, ParameterType
|
16
16
|
from .tablekeyparameter import TableKeyParameter
|
17
17
|
|
18
|
-
if TYPE_CHECKING:
|
19
|
-
from ..diaglayer import DiagLayer
|
20
|
-
|
21
18
|
|
22
19
|
@dataclass
|
23
20
|
class TableStructParameter(Parameter):
|
@@ -61,15 +58,12 @@ class TableStructParameter(Parameter):
|
|
61
58
|
self._table_key = odxlinks.resolve(self.table_key_ref, TableKeyParameter)
|
62
59
|
|
63
60
|
@override
|
64
|
-
def _resolve_snrefs(self,
|
65
|
-
super()._resolve_snrefs(
|
61
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
62
|
+
super()._resolve_snrefs(context)
|
66
63
|
|
67
64
|
if self.table_key_snref is not None:
|
68
|
-
|
69
|
-
|
70
|
-
" in TableStructParameters.",
|
71
|
-
OdxWarning,
|
72
|
-
stacklevel=1)
|
65
|
+
self._table_key = resolve_snref(self.table_key_snref, odxrequire(context.parameters),
|
66
|
+
TableKeyParameter)
|
73
67
|
|
74
68
|
@property
|
75
69
|
def table_key(self) -> TableKeyParameter:
|
@@ -86,71 +80,76 @@ class TableStructParameter(Parameter):
|
|
86
80
|
return True
|
87
81
|
|
88
82
|
@override
|
89
|
-
def
|
90
|
-
|
83
|
+
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
84
|
+
encode_state: EncodeState) -> None:
|
91
85
|
|
92
|
-
if not isinstance(physical_value, tuple) or \
|
86
|
+
if not isinstance(physical_value, (tuple, list)) or \
|
93
87
|
len(physical_value) != 2 or \
|
94
88
|
not isinstance(physical_value[0], str):
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
89
|
+
odxraise(
|
90
|
+
f"The physical value of TableStructParameter 'self.short_name' "
|
91
|
+
f"must be a tuple containing the short name of the selected table "
|
92
|
+
f"row as the first element and the physical value for the "
|
93
|
+
f"row's structure or DOP as the second.", EncodeError)
|
99
94
|
|
100
95
|
tr_short_name = physical_value[0]
|
101
96
|
|
102
97
|
# make sure that the same table row is selected for all
|
103
98
|
# TABLE-STRUCT parameters that are using the same key
|
104
99
|
tk_short_name = self.table_key.short_name
|
105
|
-
tk_value = encode_state.
|
100
|
+
tk_value = encode_state.table_keys.get(tk_short_name)
|
106
101
|
if tk_value is None:
|
107
102
|
# no value for the key has been set yet. Set it to the
|
108
103
|
# value which we are using right now
|
109
|
-
encode_state.
|
104
|
+
encode_state.table_keys[tk_short_name] = tr_short_name
|
110
105
|
elif tk_value != tr_short_name:
|
111
|
-
|
112
|
-
|
106
|
+
odxraise(
|
107
|
+
f"Cannot determine a unique value for table key '{tk_short_name}': "
|
108
|
+
f"Requested are '{tk_value}' and '{tr_short_name}'", EncodeError)
|
109
|
+
return
|
113
110
|
|
114
111
|
# deal with the static case (i.e., the table row is selected
|
115
112
|
# by the table key object itself)
|
116
|
-
if self.table_key.table_row is not None
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
113
|
+
if self.table_key.table_row is not None:
|
114
|
+
if tr_short_name is not None and self.table_key.table_row.short_name != tr_short_name:
|
115
|
+
odxraise(
|
116
|
+
f"The selected table row for the {self.short_name} "
|
117
|
+
f"parameter must be '{self.table_key.table_row.short_name}' "
|
118
|
+
f"instead of '{tr_short_name}'", EncodeError)
|
119
|
+
return
|
120
|
+
|
121
|
+
tr_short_name = self.table_key.table_row.short_name
|
121
122
|
|
122
123
|
# encode the user specified value using the structure (or DOP)
|
123
124
|
# of the selected table row
|
124
125
|
table = self.table_key.table
|
125
126
|
candidate_trs = [tr for tr in table.table_rows if tr.short_name == tr_short_name]
|
126
|
-
if len(candidate_trs)
|
127
|
-
|
128
|
-
|
127
|
+
if len(candidate_trs) == 0:
|
128
|
+
odxraise(
|
129
|
+
f"Could not find a table row named "
|
130
|
+
f"'{tr_short_name}' in table '{table.short_name}'", EncodeError)
|
131
|
+
return
|
132
|
+
elif len(candidate_trs) > 1:
|
133
|
+
odxraise(
|
134
|
+
f"Found multiple table rows named "
|
135
|
+
f"'{tr_short_name}' in table '{table.short_name}'", EncodeError)
|
136
|
+
|
129
137
|
tr = candidate_trs[0]
|
130
138
|
tr_value = physical_value[1]
|
131
139
|
|
132
|
-
bit_position = self.bit_position or 0
|
133
140
|
if tr.structure is not None:
|
134
141
|
# the selected table row references a structure
|
135
|
-
|
136
|
-
|
137
|
-
parameter_values=tr_value,
|
138
|
-
triggering_request=encode_state.triggering_request)
|
139
|
-
|
140
|
-
return tr.structure.convert_physical_to_bytes(
|
141
|
-
tr_value, inner_encode_state, bit_position=bit_position)
|
142
|
+
tr.structure.encode_into_pdu(tr_value, encode_state)
|
143
|
+
return
|
142
144
|
|
143
145
|
# if the table row does not reference a structure, it must
|
144
146
|
# point to a DOP!
|
145
147
|
if tr.dop is None:
|
146
|
-
odxraise(
|
148
|
+
odxraise(f"Neither a structure nor a DOP has been defined for table row"
|
149
|
+
f"'{tr.short_name}'")
|
150
|
+
return
|
147
151
|
|
148
|
-
|
149
|
-
tr_value, encode_state=encode_state, bit_position=bit_position)
|
150
|
-
|
151
|
-
@override
|
152
|
-
def encode_into_pdu(self, encode_state: EncodeState) -> bytes:
|
153
|
-
return super().encode_into_pdu(encode_state)
|
152
|
+
tr.dop.encode_into_pdu(tr_value, encode_state)
|
154
153
|
|
155
154
|
@override
|
156
155
|
def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
@@ -1,22 +1,20 @@
|
|
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
6
|
from typing_extensions import override
|
7
7
|
|
8
8
|
from ..dataobjectproperty import DataObjectProperty
|
9
9
|
from ..encodestate import EncodeState
|
10
|
-
from ..exceptions import odxraise, odxrequire
|
10
|
+
from ..exceptions import EncodeError, odxraise, odxrequire
|
11
11
|
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
12
|
-
from ..odxtypes import AtomicOdxType
|
12
|
+
from ..odxtypes import AtomicOdxType, ParameterValue
|
13
|
+
from ..snrefcontext import SnRefContext
|
13
14
|
from ..utils import dataclass_fields_asdict
|
14
15
|
from .parameter import ParameterType
|
15
16
|
from .parameterwithdop import ParameterWithDOP
|
16
17
|
|
17
|
-
if TYPE_CHECKING:
|
18
|
-
from ..diaglayer import DiagLayer
|
19
|
-
|
20
18
|
|
21
19
|
@dataclass
|
22
20
|
class ValueParameter(ParameterWithDOP):
|
@@ -50,8 +48,8 @@ class ValueParameter(ParameterWithDOP):
|
|
50
48
|
super()._resolve_odxlinks(odxlinks)
|
51
49
|
|
52
50
|
@override
|
53
|
-
def _resolve_snrefs(self,
|
54
|
-
super()._resolve_snrefs(
|
51
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
52
|
+
super()._resolve_snrefs(context)
|
55
53
|
|
56
54
|
if self.physical_default_value_raw is not None:
|
57
55
|
dop = odxrequire(self.dop)
|
@@ -77,16 +75,14 @@ class ValueParameter(ParameterWithDOP):
|
|
77
75
|
return True
|
78
76
|
|
79
77
|
@override
|
80
|
-
def
|
81
|
-
|
82
|
-
|
78
|
+
def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
|
79
|
+
encode_state: EncodeState) -> None:
|
80
|
+
|
83
81
|
if physical_value is None:
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
return dop.convert_physical_to_bytes(
|
92
|
-
physical_value, encode_state=encode_state, bit_position=bit_position_int)
|
82
|
+
physical_value = self._physical_default_value
|
83
|
+
if physical_value is None:
|
84
|
+
odxraise(
|
85
|
+
f"A value for parameter '{self.short_name}' must be specified"
|
86
|
+
f" because the parameter does not exhibit a default.", EncodeError)
|
87
|
+
|
88
|
+
self.dop.encode_into_pdu(physical_value, encode_state=encode_state)
|
odxtools/paramlengthinfotype.py
CHANGED
@@ -1,28 +1,46 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import TYPE_CHECKING, Any, Dict, cast
|
3
|
+
from typing import TYPE_CHECKING, Any, Dict, List, cast
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from typing_extensions import override
|
4
7
|
|
5
8
|
from .decodestate import DecodeState
|
6
9
|
from .diagcodedtype import DctType, DiagCodedType
|
7
10
|
from .encodestate import EncodeState
|
8
|
-
from .exceptions import odxraise
|
9
|
-
from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
11
|
+
from .exceptions import EncodeError, odxraise, odxrequire
|
12
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
10
13
|
from .odxtypes import AtomicOdxType, DataType
|
14
|
+
from .snrefcontext import SnRefContext
|
15
|
+
from .utils import dataclass_fields_asdict
|
11
16
|
|
12
17
|
if TYPE_CHECKING:
|
13
|
-
from .diaglayer import DiagLayer
|
14
18
|
from .parameters.lengthkeyparameter import LengthKeyParameter
|
15
19
|
|
16
20
|
|
17
21
|
@dataclass
|
18
22
|
class ParamLengthInfoType(DiagCodedType):
|
19
|
-
|
20
23
|
length_key_ref: OdxLinkRef
|
21
24
|
|
22
25
|
@property
|
23
26
|
def dct_type(self) -> DctType:
|
24
27
|
return "PARAM-LENGTH-INFO-TYPE"
|
25
28
|
|
29
|
+
@property
|
30
|
+
def length_key(self) -> "LengthKeyParameter":
|
31
|
+
return self._length_key
|
32
|
+
|
33
|
+
@staticmethod
|
34
|
+
@override
|
35
|
+
def from_et(et_element: ElementTree.Element,
|
36
|
+
doc_frags: List[OdxDocFragment]) -> "ParamLengthInfoType":
|
37
|
+
kwargs = dataclass_fields_asdict(DiagCodedType.from_et(et_element, doc_frags))
|
38
|
+
|
39
|
+
length_key_ref = odxrequire(
|
40
|
+
OdxLinkRef.from_et(et_element.find("LENGTH-KEY-REF"), doc_frags))
|
41
|
+
|
42
|
+
return ParamLengthInfoType(length_key_ref=length_key_ref, **kwargs)
|
43
|
+
|
26
44
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
27
45
|
return super()._build_odxlinks()
|
28
46
|
|
@@ -35,43 +53,47 @@ class ParamLengthInfoType(DiagCodedType):
|
|
35
53
|
else:
|
36
54
|
self._length_key = odxlinks.resolve(self.length_key_ref)
|
37
55
|
|
38
|
-
def _resolve_snrefs(self,
|
56
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
39
57
|
"""Recursively resolve any short-name references"""
|
40
|
-
super()._resolve_snrefs(
|
58
|
+
super()._resolve_snrefs(context)
|
41
59
|
|
42
|
-
@
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
def convert_internal_to_bytes(self, internal_value: AtomicOdxType, encode_state: EncodeState,
|
47
|
-
bit_position: int) -> bytes:
|
48
|
-
bit_length = encode_state.parameter_values.get(self.length_key.short_name, None)
|
60
|
+
@override
|
61
|
+
def encode_into_pdu(self, internal_value: AtomicOdxType, encode_state: EncodeState) -> None:
|
62
|
+
bit_length = encode_state.length_keys.get(self.length_key.short_name)
|
49
63
|
|
50
64
|
if bit_length is None:
|
65
|
+
# the length key is implicit, i.e., we need to set the
|
66
|
+
# value for the length key in the encode_state based on
|
67
|
+
# the value passed here.
|
51
68
|
if self.base_data_type in [
|
52
69
|
DataType.A_BYTEFIELD,
|
53
70
|
DataType.A_ASCIISTRING,
|
54
71
|
DataType.A_UTF8STRING,
|
55
72
|
]:
|
56
|
-
bit_length = 8 * len(internal_value)
|
57
|
-
|
58
|
-
bit_length = 16 * len(internal_value)
|
59
|
-
|
60
|
-
if self.base_data_type in [DataType.A_INT32, DataType.A_UINT32]:
|
73
|
+
bit_length = 8 * len(cast(str, internal_value))
|
74
|
+
elif self.base_data_type in [DataType.A_UNICODE2STRING]:
|
75
|
+
bit_length = 16 * len(cast(str, internal_value))
|
76
|
+
elif self.base_data_type in [DataType.A_INT32, DataType.A_UINT32]:
|
61
77
|
bit_length = int(internal_value).bit_length()
|
62
78
|
if self.base_data_type == DataType.A_INT32:
|
63
79
|
bit_length += 1
|
64
80
|
# Round up
|
65
81
|
bit_length = ((bit_length + 7) // 8) * 8
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
82
|
+
elif self.base_data_type == DataType.A_FLOAT32:
|
83
|
+
bit_length = 32
|
84
|
+
elif self.base_data_type == DataType.A_FLOAT64:
|
85
|
+
bit_length = 64
|
86
|
+
else:
|
87
|
+
odxraise(
|
88
|
+
f"Cannot determine size of an object of type "
|
89
|
+
f"{self.base_data_type.value}", EncodeError)
|
90
|
+
return
|
91
|
+
|
92
|
+
encode_state.length_keys[self.length_key.short_name] = bit_length
|
93
|
+
|
94
|
+
encode_state.emplace_atomic_value(
|
95
|
+
internal_value=internal_value,
|
96
|
+
used_mask=None,
|
75
97
|
bit_length=bit_length,
|
76
98
|
base_data_type=self.base_data_type,
|
77
99
|
is_highlow_byte_order=self.is_highlow_byte_order,
|
@@ -82,7 +104,7 @@ class ParamLengthInfoType(DiagCodedType):
|
|
82
104
|
if self.length_key.short_name not in decode_state.length_keys:
|
83
105
|
odxraise(f"Unspecified mandatory length key parameter "
|
84
106
|
f"{self.length_key.short_name}")
|
85
|
-
decode_state.cursor_bit_position =
|
107
|
+
decode_state.cursor_bit_position = 0
|
86
108
|
return cast(None, AtomicOdxType)
|
87
109
|
|
88
110
|
bit_length = decode_state.length_keys[self.length_key.short_name]
|
@@ -91,10 +113,8 @@ class ParamLengthInfoType(DiagCodedType):
|
|
91
113
|
bit_length = 0
|
92
114
|
|
93
115
|
# Extract the internal value and return.
|
94
|
-
|
116
|
+
return decode_state.extract_atomic_value(
|
95
117
|
bit_length,
|
96
118
|
self.base_data_type,
|
97
119
|
self.is_highlow_byte_order,
|
98
120
|
)
|
99
|
-
|
100
|
-
return value
|
odxtools/parentref.py
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
+
from copy import deepcopy
|
2
3
|
from dataclasses import dataclass
|
3
4
|
from typing import TYPE_CHECKING, Any, Dict, List
|
4
5
|
from xml.etree import ElementTree
|
5
6
|
|
6
7
|
from .exceptions import odxrequire
|
7
8
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
9
|
+
from .snrefcontext import SnRefContext
|
10
|
+
from .utils import dataclass_fields_asdict
|
8
11
|
|
9
12
|
if TYPE_CHECKING:
|
10
|
-
from .diaglayer import DiagLayer
|
13
|
+
from .diaglayers.diaglayer import DiagLayer
|
11
14
|
|
12
15
|
|
13
16
|
@dataclass
|
@@ -76,5 +79,16 @@ class ParentRef:
|
|
76
79
|
else:
|
77
80
|
self._layer = odxlinks.resolve(self.layer_ref)
|
78
81
|
|
79
|
-
def _resolve_snrefs(self,
|
82
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
80
83
|
pass
|
84
|
+
|
85
|
+
def __deepcopy__(self, memo: Dict[int, Any]) -> Any:
|
86
|
+
cls = self.__class__
|
87
|
+
result = cls.__new__(cls)
|
88
|
+
memo[id(self)] = result
|
89
|
+
|
90
|
+
fields = dataclass_fields_asdict(self)
|
91
|
+
for name, value in fields.items():
|
92
|
+
setattr(result, name, deepcopy(value))
|
93
|
+
|
94
|
+
return result
|