Skip to content

Commit

Permalink
fix en- and decoding of environment data descriptions
Browse files Browse the repository at this point in the history
it turns out that the specification only mandates that the base data
type of the DOP used by the referenced parameter must be A_UINT32, but
the DOP does not need to be a DTC-DOP.

Signed-off-by: Andreas Lauser <andreas.lauser@mbition.io>
Signed-off-by: Katja Köhler <katja.koehler@mercedes-benz.com>
  • Loading branch information
andlaus committed Jan 14, 2025
1 parent 03a096f commit 41494f9
Showing 1 changed file with 93 additions and 43 deletions.
136 changes: 93 additions & 43 deletions odxtools/environmentdatadescription.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@
from typing_extensions import override

from .complexdop import ComplexDop
from .dataobjectproperty import DataObjectProperty
from .decodestate import DecodeState
from .dtcdop import DtcDop
from .encodestate import EncodeState
from .environmentdata import EnvironmentData
from .exceptions import odxraise, odxrequire
from .nameditemlist import NamedItemList
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
from .odxtypes import ParameterValue, ParameterValueDict
from .odxtypes import DataType, ParameterValue, ParameterValueDict
from .parameters.parameter import Parameter
from .parameters.valueparameter import ValueParameter
from .snrefcontext import SnRefContext
from .utils import dataclass_fields_asdict

Expand Down Expand Up @@ -116,40 +118,64 @@ def encode_into_pdu(self, physical_value: Optional[ParameterValue],
"""Convert a physical value into bytes and emplace them into a PDU.
"""

# retrieve the relevant DTC parameter which must be located in
# front of the environment data description.
# retrieve the DTC as a numerical value from the referenced
# parameter (which must be located somewhere before the
# parameter using the environment data description)
if self.param_snref is None:
odxraise("Specifying the DTC parameter for environment data "
"descriptions via SNPATHREF is not supported yet")
return None

dtc_param: Optional[Parameter] = None
dtc_dop: Optional[DtcDop] = None
dtc_param_value: Optional[ParameterValue] = None
numerical_dtc_value: Optional[ParameterValue] = None
for prev_param, prev_param_value in reversed(encode_state.journal):
if prev_param.short_name == self.param_snref:
dtc_param = prev_param
prev_dop = getattr(prev_param, "dop", None)
if not isinstance(prev_dop, DtcDop):
odxraise(f"The DOP of the parameter referenced by environment data "
f"descriptions must be a DTC-DOP (is '{type(prev_dop).__name__}')")
if not isinstance(prev_param, ValueParameter):
odxraise(
f"The parameter referenced by environment data descriptions "
f"must use a VALUE-PARAMETER (encountered {type(prev_param).__name__} "
f"for reference '{self.param_snref}' of ENV-DATA-DESC '{self.short_name}')")
return
dtc_dop = prev_dop
dtc_param_value = prev_param_value

prev_dop = prev_param.dop
if isinstance(prev_dop, DtcDop):
if prev_dop.diag_coded_type.base_data_type != DataType.A_UINT32:
odxraise(f"The data type used by the DOP of the parameter referenced "
f"by environment data descriptions must be A_UINT32 "
f"(encountered '{prev_dop.diag_coded_type.base_data_type.value}')")
return

if prev_param_value is None:
odxraise()
return

numerical_dtc_value = prev_dop.convert_to_numerical_trouble_code(
prev_param_value)
elif isinstance(prev_dop, DataObjectProperty):
if prev_dop.diag_coded_type.base_data_type != DataType.A_UINT32:
odxraise(f"The data type used by the DOP of the parameter referenced "
f"by environment data descriptions must be A_UINT32 "
f"(encountered '{prev_dop.diag_coded_type.base_data_type.value}')")
return

if not isinstance(prev_param_value, (int, str)):
odxraise()
return

numerical_dtc_value = prev_dop.compu_method.convert_physical_to_internal(
prev_param_value)
else:
odxraise(f"The DOP of the parameter referenced "
f"by environment data descriptions must use a simple DOP or a DTC-DOP "
f"(encountered '{type(prev_dop).__name__}')")
return

break

if dtc_param is None:
if numerical_dtc_value is None:
odxraise("Environment data description parameters are only allowed following "
"the referenced value parameter.")
return

if dtc_param_value is None or dtc_dop is None:
# this should never happen
odxraise()
return

numerical_dtc = dtc_dop.convert_to_numerical_trouble_code(dtc_param_value)

# deal with the "all value" environment data. This holds
# parameters that are common to all DTCs. Be aware that the
# specification mandates that there is at most one such
Expand All @@ -165,7 +191,7 @@ def encode_into_pdu(self, physical_value: Optional[ParameterValue],
# find the environment data corresponding to the given trouble
# code
for env_data in self.env_datas:
if numerical_dtc in env_data.dtc_values:
if numerical_dtc_value in env_data.dtc_values:
tmp = encode_state.allow_unknown_parameters
encode_state.allow_unknown_parameters = True
env_data.encode_into_pdu(physical_value, encode_state)
Expand All @@ -177,40 +203,64 @@ def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
"""Extract the bytes from a PDU and convert them to a physical value.
"""

# retrieve the relevant DTC parameter which must be located in
# front of the environment data description.
# retrieve the DTC as a numerical value from the referenced
# parameter (which must be located somewhere before the
# parameter using the environment data description)
if self.param_snref is None:
odxraise("Specifying the DTC parameter for environment data "
"descriptions via SNPATHREF is not supported yet")
return None

dtc_param: Optional[Parameter] = None
dtc_dop: Optional[DtcDop] = None
dtc_param_value: Optional[ParameterValue] = None
numerical_dtc_value: Optional[ParameterValue] = None
for prev_param, prev_param_value in reversed(decode_state.journal):
if prev_param.short_name == self.param_snref:
dtc_param = prev_param
prev_dop = getattr(prev_param, "dop", None)
if not isinstance(prev_dop, DtcDop):
odxraise(f"The DOP of the parameter referenced by environment data "
f"descriptions must be a DTC-DOP (is '{type(prev_dop).__name__}')")
if not isinstance(prev_param, ValueParameter):
odxraise(
f"The parameter referenced by environment data descriptions "
f"must use a VALUE-PARAMETER (encountered {type(prev_param).__name__} "
f"for reference '{self.param_snref}' of ENV-DATA-DESC '{self.short_name}')")
return
dtc_dop = prev_dop
dtc_param_value = prev_param_value

prev_dop = prev_param.dop
if isinstance(prev_dop, DtcDop):
if prev_dop.diag_coded_type.base_data_type != DataType.A_UINT32:
odxraise(f"The data type used by the DOP of the parameter referenced "
f"by environment data descriptions must be A_UINT32 "
f"(encountered '{prev_dop.diag_coded_type.base_data_type.value}')")
return

if prev_param_value is None:
odxraise()
return

numerical_dtc_value = prev_dop.convert_to_numerical_trouble_code(
prev_param_value)
elif isinstance(prev_dop, DataObjectProperty):
if prev_dop.diag_coded_type.base_data_type != DataType.A_UINT32:
odxraise(f"The data type used by the DOP of the parameter referenced "
f"by environment data descriptions must be A_UINT32 "
f"(encountered '{prev_dop.diag_coded_type.base_data_type.value}')")
return

if not isinstance(prev_param_value, (int, str)):
odxraise()
return

numerical_dtc_value = prev_dop.compu_method.convert_physical_to_internal(
prev_param_value)
else:
odxraise(f"The DOP of the parameter referenced "
f"by environment data descriptions must use a simple DOP or a DTC-DOP "
f"(encountered '{type(prev_dop).__name__}')")
return

break

if dtc_param is None:
if numerical_dtc_value is None:
odxraise("Environment data description parameters are only allowed following "
"the referenced value parameter.")
return

if dtc_param_value is None or dtc_dop is None:
# this should never happen
odxraise()
return

numerical_dtc = dtc_dop.convert_to_numerical_trouble_code(dtc_param_value)

result: ParameterValueDict = {}

# deal with the "all value" environment data. This holds
Expand All @@ -228,7 +278,7 @@ def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
# find the environment data corresponding to the given trouble
# code
for env_data in self.env_datas:
if numerical_dtc in env_data.dtc_values:
if numerical_dtc_value in env_data.dtc_values:
tmp = env_data.decode_from_pdu(decode_state)
if not isinstance(tmp, dict):
odxraise()
Expand Down

0 comments on commit 41494f9

Please sign in to comment.