diff --git a/doc/source/udsoncan/client.rst b/doc/source/udsoncan/client.rst index 7289ce3..2b45133 100755 --- a/doc/source/udsoncan/client.rst +++ b/doc/source/udsoncan/client.rst @@ -248,6 +248,17 @@ See :ref:`an example ` Default value is True + +.. _config_nrc78_callback: + +.. attribute:: nrc78_callback + :annotation: (callable) + + A callback to be called each time a server returns a negative response with code NRC 0x78 (:attr:`RequestCorrectlyReceived_ResponsePending`). + When the response is received, the client will call the callback, then go back into a wait state for the next response. + + Can be useful to send a :ref:`TesterPresent` request/response before blocking again. + ------------- Suppress positive response diff --git a/doc/source/udsoncan/request_response.rst b/doc/source/udsoncan/request_response.rst index bc3e168..9b0f100 100755 --- a/doc/source/udsoncan/request_response.rst +++ b/doc/source/udsoncan/request_response.rst @@ -52,7 +52,7 @@ Response Response Codes ############## -.. autoclass:: udsoncan::Response.Code +.. autoclass:: udsoncan.ResponseCode.ResponseCode :members: :undoc-members: :member-order: bysource diff --git a/test/client/test_client.py b/test/client/test_client.py index 857e498..1753554 100755 --- a/test/client/test_client.py +++ b/test/client/test_client.py @@ -293,3 +293,21 @@ def _test_suppress_positive_response_wait_nrc_case5(self): with self.udsclient.suppress_positive_response(wait_nrc=True): resp = self.udsclient.tester_present() self.assertIsNotNone(resp) + + def test_nrc78_callback(self): + request = self.conn.touserqueue.get(timeout=0.2) + self.conn.fromuserqueue.put(b"\x7F\x3E\x78") + self.conn.fromuserqueue.put(b"\x7E\x00") + + def _test_nrc78_callback(self): + class Container: + def __init__(self): + self.called = False + container = Container() + def callback(): + container.called = True + self.udsclient.config['nrc78_callback'] = callback + req = Request(service=services.TesterPresent, subfunction=0) + response = self.udsclient.send_request(req) + self.assertTrue(response.positive) + diff --git a/udsoncan/client.py b/udsoncan/client.py index 685f9cd..c01b788 100755 --- a/udsoncan/client.py +++ b/udsoncan/client.py @@ -2246,6 +2246,9 @@ def send_request(self, request: Request, timeout: int = -1) -> Optional[Response response.code_name, response.code)) if response.code == Response.Code.RequestCorrectlyReceived_ResponsePending: + if self.config['nrc78_callback'] is not None: + self.config['nrc78_callback']() + done_receiving = False if not using_p2_star: # Received a 0x78 NRC: timeout is now set to P2* diff --git a/udsoncan/configs.py b/udsoncan/configs.py index 27ef71d..10a45b2 100755 --- a/udsoncan/configs.py +++ b/udsoncan/configs.py @@ -20,5 +20,6 @@ 'p2_star_timeout': 5, 'standard_version': latest_standard, # 2006, 2013, 2020 'use_server_timing': True, - 'extended_data_size': None + 'extended_data_size': None, + 'nrc78_callback':None }) diff --git a/udsoncan/typing.py b/udsoncan/typing.py index a93199f..b79ce07 100644 --- a/udsoncan/typing.py +++ b/udsoncan/typing.py @@ -10,6 +10,7 @@ def __init_subclass__(cls, *args, **kwargs): from typing import TypedDict SecurityAlgoType = Callable[[int, bytes, Any], bytes] +Nrc78CallbackType = Callable[[], None] CodecDefinition = Union[str, DidCodec, Type[DidCodec]] @@ -45,3 +46,4 @@ class ClientConfig(TypedDict, total=False): use_server_timing: bool logger_name: str extended_data_size: Optional[Union[int, Dict[int, int]]] + nrc78_callback:Optional[Nrc78CallbackType]