Skip to content

Commit ecc4d14

Browse files
authored
Merge pull request #379 from andlaus/fix_env_data_desc_coding
fix en- and decoding of environment data descriptions
2 parents 30fb09b + c068384 commit ecc4d14

File tree

1 file changed

+77
-47
lines changed

1 file changed

+77
-47
lines changed

odxtools/environmentdatadescription.py

Lines changed: 77 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,20 @@
66
from typing_extensions import override
77

88
from .complexdop import ComplexDop
9+
from .dataobjectproperty import DataObjectProperty
910
from .decodestate import DecodeState
1011
from .dtcdop import DtcDop
1112
from .encodestate import EncodeState
1213
from .environmentdata import EnvironmentData
1314
from .exceptions import odxraise, odxrequire
1415
from .nameditemlist import NamedItemList
1516
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
16-
from .odxtypes import ParameterValue, ParameterValueDict
17+
from .odxtypes import DataType, ParameterValue, ParameterValueDict
18+
from .parameters.codedconstparameter import CodedConstParameter
1719
from .parameters.parameter import Parameter
20+
from .parameters.parameterwithdop import ParameterWithDOP
21+
from .parameters.physicalconstantparameter import PhysicalConstantParameter
22+
from .parameters.valueparameter import ValueParameter
1823
from .snrefcontext import SnRefContext
1924
from .utils import dataclass_fields_asdict
2025

@@ -116,40 +121,26 @@ def encode_into_pdu(self, physical_value: Optional[ParameterValue],
116121
"""Convert a physical value into bytes and emplace them into a PDU.
117122
"""
118123

119-
# retrieve the relevant DTC parameter which must be located in
120-
# front of the environment data description.
124+
# retrieve the DTC as a numerical value from the referenced
125+
# parameter (which must be located somewhere before the
126+
# parameter using the environment data description)
121127
if self.param_snref is None:
122128
odxraise("Specifying the DTC parameter for environment data "
123129
"descriptions via SNPATHREF is not supported yet")
124130
return None
125131

126-
dtc_param: Optional[Parameter] = None
127-
dtc_dop: Optional[DtcDop] = None
128-
dtc_param_value: Optional[ParameterValue] = None
132+
numerical_dtc_value: Optional[ParameterValue] = None
129133
for prev_param, prev_param_value in reversed(encode_state.journal):
130134
if prev_param.short_name == self.param_snref:
131-
dtc_param = prev_param
132-
prev_dop = getattr(prev_param, "dop", None)
133-
if not isinstance(prev_dop, DtcDop):
134-
odxraise(f"The DOP of the parameter referenced by environment data "
135-
f"descriptions must be a DTC-DOP (is '{type(prev_dop).__name__}')")
136-
return
137-
dtc_dop = prev_dop
138-
dtc_param_value = prev_param_value
135+
numerical_dtc_value = self._get_numerical_dtc_from_parameter(
136+
prev_param, prev_param_value)
139137
break
140138

141-
if dtc_param is None:
139+
if numerical_dtc_value is None:
142140
odxraise("Environment data description parameters are only allowed following "
143-
"the referenced value parameter.")
144-
return
145-
146-
if dtc_param_value is None or dtc_dop is None:
147-
# this should never happen
148-
odxraise()
141+
"the referenced parameter.")
149142
return
150143

151-
numerical_dtc = dtc_dop.convert_to_numerical_trouble_code(dtc_param_value)
152-
153144
# deal with the "all value" environment data. This holds
154145
# parameters that are common to all DTCs. Be aware that the
155146
# specification mandates that there is at most one such
@@ -165,7 +156,7 @@ def encode_into_pdu(self, physical_value: Optional[ParameterValue],
165156
# find the environment data corresponding to the given trouble
166157
# code
167158
for env_data in self.env_datas:
168-
if numerical_dtc in env_data.dtc_values:
159+
if numerical_dtc_value in env_data.dtc_values:
169160
tmp = encode_state.allow_unknown_parameters
170161
encode_state.allow_unknown_parameters = True
171162
env_data.encode_into_pdu(physical_value, encode_state)
@@ -177,40 +168,26 @@ def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
177168
"""Extract the bytes from a PDU and convert them to a physical value.
178169
"""
179170

180-
# retrieve the relevant DTC parameter which must be located in
181-
# front of the environment data description.
171+
# retrieve the DTC as a numerical value from the referenced
172+
# parameter (which must be located somewhere before the
173+
# parameter using the environment data description)
182174
if self.param_snref is None:
183175
odxraise("Specifying the DTC parameter for environment data "
184176
"descriptions via SNPATHREF is not supported yet")
185177
return None
186178

187-
dtc_param: Optional[Parameter] = None
188-
dtc_dop: Optional[DtcDop] = None
189-
dtc_param_value: Optional[ParameterValue] = None
179+
numerical_dtc_value: Optional[ParameterValue] = None
190180
for prev_param, prev_param_value in reversed(decode_state.journal):
191181
if prev_param.short_name == self.param_snref:
192-
dtc_param = prev_param
193-
prev_dop = getattr(prev_param, "dop", None)
194-
if not isinstance(prev_dop, DtcDop):
195-
odxraise(f"The DOP of the parameter referenced by environment data "
196-
f"descriptions must be a DTC-DOP (is '{type(prev_dop).__name__}')")
197-
return
198-
dtc_dop = prev_dop
199-
dtc_param_value = prev_param_value
182+
numerical_dtc_value = self._get_numerical_dtc_from_parameter(
183+
prev_param, prev_param_value)
200184
break
201185

202-
if dtc_param is None:
186+
if numerical_dtc_value is None:
203187
odxraise("Environment data description parameters are only allowed following "
204-
"the referenced value parameter.")
188+
"the referenced parameter.")
205189
return
206190

207-
if dtc_param_value is None or dtc_dop is None:
208-
# this should never happen
209-
odxraise()
210-
return
211-
212-
numerical_dtc = dtc_dop.convert_to_numerical_trouble_code(dtc_param_value)
213-
214191
result: ParameterValueDict = {}
215192

216193
# deal with the "all value" environment data. This holds
@@ -228,11 +205,64 @@ def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
228205
# find the environment data corresponding to the given trouble
229206
# code
230207
for env_data in self.env_datas:
231-
if numerical_dtc in env_data.dtc_values:
208+
if numerical_dtc_value in env_data.dtc_values:
232209
tmp = env_data.decode_from_pdu(decode_state)
233210
if not isinstance(tmp, dict):
234211
odxraise()
235212
result.update(tmp)
236213
break
237214

238215
return result
216+
217+
def _get_numerical_dtc_from_parameter(self, param: Parameter,
218+
param_value: Optional[ParameterValue]) -> int:
219+
if isinstance(param, ParameterWithDOP):
220+
dop = param.dop
221+
if not isinstance(dop, (DataObjectProperty, DtcDop)):
222+
odxraise(f"The DOP of the parameter referenced by environment data descriptions "
223+
f"must use either be DataObjectProperty or a DtcDop (encountered "
224+
f"{type(param).__name__} for parameter '{self.param.short_name}' "
225+
f"of ENV-DATA-DESC '{self.short_name}')")
226+
return 0
227+
228+
if dop.diag_coded_type.base_data_type != DataType.A_UINT32:
229+
odxraise(f"The data type used by the DOP of the parameter referenced "
230+
f"by environment data descriptions must be A_UINT32 "
231+
f"(encountered '{dop.diag_coded_type.base_data_type.value}')")
232+
233+
if param_value is None:
234+
if isinstance(param, ValueParameter):
235+
param_value = param.physical_default_value
236+
elif isinstance(param, PhysicalConstantParameter):
237+
param_value = param.physical_constant_value
238+
else:
239+
odxraise() # make mypy happy...
240+
return
241+
242+
if isinstance(dop, DtcDop):
243+
return dop.convert_to_numerical_trouble_code(odxrequire(param_value))
244+
elif isinstance(dop, DataObjectProperty):
245+
return int(dop.compu_method.convert_physical_to_internal(
246+
param_value)) # type: ignore[arg-type]
247+
248+
odxraise() # not reachable...
249+
250+
elif isinstance(param, CodedConstParameter):
251+
if param.diag_coded_type.base_data_type != DataType.A_UINT32:
252+
odxraise(f"The data type used by the parameter referenced "
253+
f"by environment data descriptions must be A_UINT32 "
254+
f"(encountered '{param.diag_coded_type.base_data_type.value}')")
255+
256+
return param.coded_value
257+
258+
if not isinstance(param.coded_value, int):
259+
odxraise()
260+
261+
return param.coded_value
262+
263+
else:
264+
odxraise(f"The parameter referenced by environment data descriptions "
265+
f"must be a parameter that either specifies a DOP or a constant "
266+
f"(encountered {type(param).__name__} for reference '{self.param_snref}' of "
267+
f"ENV-DATA-DESC '{self.short_name}')")
268+
return 0

0 commit comments

Comments
 (0)