66from typing_extensions import override
77
88from .complexdop import ComplexDop
9+ from .dataobjectproperty import DataObjectProperty
910from .decodestate import DecodeState
1011from .dtcdop import DtcDop
1112from .encodestate import EncodeState
1213from .environmentdata import EnvironmentData
1314from .exceptions import odxraise , odxrequire
1415from .nameditemlist import NamedItemList
1516from .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
1719from .parameters .parameter import Parameter
20+ from .parameters .parameterwithdop import ParameterWithDOP
21+ from .parameters .physicalconstantparameter import PhysicalConstantParameter
22+ from .parameters .valueparameter import ValueParameter
1823from .snrefcontext import SnRefContext
1924from .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