11import struct
2- from udsoncan import Dtc , check_did_config , make_did_codec_from_definition , fetch_codec_definition_from_config , latest_standard , DIDConfig
2+ from udsoncan import Dtc , check_did_config , make_did_codec_from_definition , fetch_codec_definition_from_config , latest_standard , valid_standards , DIDConfig
33from udsoncan .Request import Request
44from udsoncan .Response import Response
55from udsoncan .exceptions import *
@@ -168,10 +168,12 @@ def assert_extended_data_size_int_or_dict(cls,
168168 tools .validate_int (extended_data_size [dtcid ], min = 0 , max = 0xFFF , name = 'Extended data size for DTC=0x%06x' % dtcid )
169169
170170 @classmethod
171- def assert_functional_group_id (cls , functional_group_id : Optional [int ], subfunction ) -> None :
171+ def assert_functional_group_id (cls , functional_group_id : Optional [int ], subfunction : int ) -> None :
172172 if functional_group_id is None :
173173 raise ValueError ('functional_group_id must be provided for subfunction 0x%02x' % subfunction )
174- tools .validate_int (functional_group_id , min = 0 , max = 0xFE , name = 'Functional Group ID' )
174+ # ISO-14229:2020 Disallow a value of 0xFF. But ISO-27145-3 Defines it as "All functional system groups".
175+ # Allowing 0xFF because of the ambiguity
176+ tools .validate_int (functional_group_id , min = 0 , max = 0xFF , name = 'Functional Group ID' )
175177
176178 @classmethod
177179 def pack_dtc (cls , dtcid : int ) -> bytes :
@@ -180,6 +182,9 @@ def pack_dtc(cls, dtcid: int) -> bytes:
180182 @classmethod
181183 def check_subfunction_valid (cls , subfunction : int , standard_version : int = latest_standard ) -> None :
182184 tools .validate_int (subfunction , min = 1 , max = 0xFF , name = 'Subfunction' )
185+ if standard_version not in valid_standards :
186+ raise ValueError (f"Standard version { standard_version } is not valid" )
187+
183188 vlist = vars (cls )
184189 ok = True
185190 for v in vlist :
@@ -190,20 +195,33 @@ def check_subfunction_valid(cls, subfunction: int, standard_version: int = lates
190195 raise ValueError ('Unknown subfunction : 0x%02x' , subfunction )
191196
192197 # These subfunction have been added in the 2020 version of the standard
193- subfunction2020 = [
194- cls .Subfunction .reportUserDefMemoryDTCByStatusMask ,
195- cls .Subfunction .reportDTCExtDataRecordByRecordNumber ,
196- cls .Subfunction .reportUserDefMemoryDTCSnapshotRecordByDTCNumber ,
197- cls .Subfunction .reportUserDefMemoryDTCExtDataRecordByDTCNumber ,
198- cls .Subfunction .reportSupportedDTCExtDataRecord ,
199- cls .Subfunction .reportWWHOBDDTCByMaskRecord ,
200- cls .Subfunction .reportWWHOBDDTCWithPermanentStatus ,
201- cls .Subfunction .reportDTCInformationByDTCReadinessGroupIdentifier ,
202- ]
203-
204- if subfunction in subfunction2020 and standard_version < 2020 :
205- raise NotImplementedError ('The subfunction 0x%02x has been introduced in standard version 2020 but decoding is requested to be done as per %d version' % (
206- subfunction , standard_version ))
198+ subfunction_disallow_map :Dict [int , List [int ]] = {
199+ 2006 : [
200+ cls .Subfunction .reportDTCExtDataRecordByRecordNumber ,
201+ cls .Subfunction .reportUserDefMemoryDTCByStatusMask ,
202+ cls .Subfunction .reportUserDefMemoryDTCSnapshotRecordByDTCNumber ,
203+ cls .Subfunction .reportUserDefMemoryDTCExtDataRecordByDTCNumber ,
204+ #cls.Subfunction.reportDTCExtendedDataRecordIdentification, # Not implemented
205+ cls .Subfunction .reportWWHOBDDTCByMaskRecord ,
206+ cls .Subfunction .reportWWHOBDDTCWithPermanentStatus ,
207+ cls .Subfunction .reportDTCInformationByDTCReadinessGroupIdentifier ,
208+ ],
209+ 2013 : [
210+ #cls.Subfunction.reportDTCExtendedDataRecordIdentification, # Not implemented
211+ cls .Subfunction .reportDTCInformationByDTCReadinessGroupIdentifier ,
212+ ],
213+ 2020 : [
214+ cls .Subfunction .reportMirrorMemoryDTCByStatusMask ,
215+ #cls.Subfunction.reportMirrorMemoryDTCExtDataRecordByDTCNumber, # Not implemented
216+ cls .Subfunction .reportNumberOfMirrorMemoryDTCByStatusMask ,
217+ #cls.Subfunction.reportNumberOfEmissionsOBDDTCByStatusMask, # Not implemented
218+ #cls.Subfunction.reportEmissionsOBDDTCByStatusMask, # Not implemented
219+ ]
220+ }
221+
222+ if standard_version in subfunction_disallow_map :
223+ if subfunction in subfunction_disallow_map [standard_version ]:
224+ raise NotImplementedError (f"Subfunction 0x{ subfunction :02x} is not allowed by ISO-14229:{ standard_version } . Check for a different version of the standard" )
207225
208226 @classmethod
209227 def make_request (cls ,
@@ -248,6 +266,8 @@ def make_request(cls,
248266
249267
250268 :raises ValueError: If parameters are out of range, missing or wrong type
269+ :raises NotImplementedError: If the requested subfunction is not supported by the active ISO-14229 standard version
270+
251271 """
252272
253273 # Request grouping for subfunctions that have the same request format
@@ -391,11 +411,11 @@ def make_request(cls,
391411 elif subfunction == ReadDTCInformation .Subfunction .reportWWHOBDDTCByMaskRecord :
392412 cls .assert_status_mask (status_mask , subfunction )
393413 cls .assert_severity_mask (severity_mask , subfunction )
394- cls .assert_functional_group_id (functional_group_id , subfunction ) # Maximum specified by ISO-14229:2020
414+ cls .assert_functional_group_id (functional_group_id , subfunction )
395415 req .data = struct .pack ('BBB' , functional_group_id , status_mask , severity_mask )
396416
397417 elif subfunction == ReadDTCInformation .Subfunction .reportWWHOBDDTCWithPermanentStatus :
398- cls .assert_functional_group_id (functional_group_id , subfunction ) # Maximum specified by ISO-14229:2020
418+ cls .assert_functional_group_id (functional_group_id , subfunction )
399419 req .data = struct .pack ('B' , functional_group_id )
400420
401421 return req
@@ -852,9 +872,6 @@ def interpret_response(cls,
852872 raise InvalidResponseException (response , 'Incomplete response from server. Missing DTCExtDataRecordNumber' )
853873
854874 record_number = int (response .data [1 ])
855- if record_number > 0xEF :
856- raise InvalidResponseException (
857- response , 'Server returned a RecordNumber of %d which is out of range (00-EF) according to ISO-14229:2020' , record_number )
858875
859876 actual_byte = 2
860877 received_dtcs = set ()
@@ -931,9 +948,8 @@ def interpret_response(cls,
931948 else :
932949 raise NotImplementedError ("Unreachable code" )
933950
934- if response .service_data .functional_group_id > 0xFE :
935- raise InvalidResponseException (response , "FunctionalGroupIdentifier returned by the server is not smaller or equal than 0xFE" )
936-
951+ # Don't check functional_group_id on purpose. range 0 to FF is accepted
952+
937953 if response .service_data .dtc_format not in [Dtc .Format .SAE_J2012_DA_DTCFormat_04 , Dtc .Format .SAE_J1939_73 ]:
938954 raise InvalidResponseException (response , "DTCFormatIdentifier returned by the server is not one of the following: SAE_J2012-DA_DTCFormat_04 (4), SAE_J1939-73_DTCFormat(2). Got 0x%02x" % response .service_data .dtc_format )
939955
0 commit comments