Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion doc/source/udsoncan/client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,18 @@ See :ref:`an example <example_security_algo>`
.. attribute:: use_server_timing
:annotation: (bool)

When using 2013 standard or above, the server is required to provide its P2 and P2* timing values with a DiagnosticSessionControl request. By setting this parameter to ``True``, the value received from the server will be used. When ``False``, these timing values will be ignored and local configuration timing will be used. Note that no timeout value can exceed the ``config['request_timeout']`` as it is meant to avoid the client from hanging for too long.
When using 2013 standard or above, the server is required to provide its P2 and P2* timing values with a DiagnosticSessionControl request.
By setting this parameter to ``True``, the value received from the server will be used. When ``False``, these timing values will be ignored and local configuration timing will be used.
Note that no timeout value can exceed the ``config['request_timeout']`` as it is meant to avoid the client from hanging for too long.

This parameter has no effect when ``config['standard_version']`` is set to ``2006``.

Default value is True

.. note::

The timeouts provided by the server can be obtained via :meth:`get_session_timing<Client.get_session_timing>`


.. _config_nrc78_callback:

Expand Down Expand Up @@ -320,6 +326,24 @@ When using that feature, the client will process the response from the server ju

-----

Session timings
---------------

When a request is performed, the client uses the P2 & P2* timeouts value provided by the server in a response to :meth:`change_session<udsoncan.client.Client.change_session>`.
If :meth:`change_session<udsoncan.client.Client.change_session>` is not called yet (or if the standard used is 2006), the values from the configuration will be used : :ref:`p2_timeout<config_p2_timeout>` & :ref:`p2_star_timeout<config_p2_star_timeout>`

The client can provide the received P2 & P2* timeouts value via :meth:`get_session_timing<udsoncan.client.Client.get_session_timing>`

.. automethod:: udsoncan.client.Client.get_session_timing

.. autoclass:: udsoncan.client.SessionTiming
:exclude-members: __init__, __new__
:members:


-----


Methods by services
-------------------

Expand Down
8 changes: 4 additions & 4 deletions test/client/test_diagnostic_session_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ def _test_dsc_success_2013_plus(self):
self.assertEqual(response.service_data.session_param_records, b"\x99\x88\x12\x34")
self.assertEqual(response.service_data.p2_server_max, (0x9988) / 1000)
self.assertEqual(response.service_data.p2_star_server_max, 0x1234 * 10 / 1000)
self.assertEqual(self.udsclient.session_timing['p2_server_max'], response.service_data.p2_server_max)
self.assertEqual(self.udsclient.session_timing['p2_star_server_max'], response.service_data.p2_star_server_max)
self.assertEqual(self.udsclient.get_session_timing().p2_server_max, response.service_data.p2_server_max)
self.assertEqual(self.udsclient.get_session_timing().p2_star_server_max, response.service_data.p2_star_server_max)

def test_dsc_success_2013_plus_ignore_server_timing(self):
request = self.conn.touserqueue.get(timeout=0.2)
Expand All @@ -50,8 +50,8 @@ def _test_dsc_success_2013_plus_ignore_server_timing(self):
self.assertEqual(response.service_data.session_param_records, b"\x99\x88\x12\x34")
self.assertEqual(response.service_data.p2_server_max, 0x9988 / 1000)
self.assertEqual(response.service_data.p2_star_server_max, 0x1234 * 10 / 1000)
self.assertIsNone(self.udsclient.session_timing['p2_server_max'])
self.assertIsNone(self.udsclient.session_timing['p2_star_server_max'])
self.assertIsNone(self.udsclient.get_session_timing().p2_server_max)
self.assertIsNone(self.udsclient.get_session_timing().p2_star_server_max)

def test_dsc_success_spr(self):
request = self.conn.touserqueue.get(timeout=0.2)
Expand Down
29 changes: 23 additions & 6 deletions udsoncan/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,17 @@
from typing import Callable, Optional, Union, Dict, List, Any, cast, Type


class SessionTiming(TypedDict):
class SessionTiming:
"""Container for server provided P2 & P2* timeouts."""

p2_server_max: Optional[float]
"""P2 server max provided by the server. ``None`` if not provided yet """
p2_star_server_max: Optional[float]
"""P2* server max provided by the server. ``None`` if not provided yet """

def __init__(self, p2_server_max:Optional[float]=None, p2_star_server_max:Optional[float]=None) -> None:
self.p2_server_max = p2_server_max
self.p2_star_server_max = p2_star_server_max


class Client:
Expand Down Expand Up @@ -111,7 +119,7 @@ def __init__(self, conn: BaseConnection, config: ClientConfig = default_client_c
self.payload_override = Client.PayloadOverrider()
self.last_response = None

self.session_timing = cast(SessionTiming, dict(p2_server_max=None, p2_star_server_max=None)) # python 3.7 cast
self.session_timing = SessionTiming(p2_server_max=None, p2_star_server_max=None)

self.refresh_config()

Expand Down Expand Up @@ -204,6 +212,15 @@ def decorated(self: "Client", *args, **kwargs):
def service_log_prefix(self, service: Type[BaseService]):
return "%s<0x%02x>" % (service.get_name(), service.request_id())

def get_session_timing(self) -> SessionTiming:
"""Return the session timing provided by the server, including P2 & P2* timeouts.
If the timeout values are ``None``, it means that no timing has been given by the server yet and the timings form the client configuration
(:ref:`p2_timeout<config_p2_timeout>`, :ref:`p2_star_timeout<config_p2_star_timeout>`)

:return: The session timings
"""
return self.session_timing

@standard_error_management
def change_session(self, newsession: int) -> Optional[services.DiagnosticSessionControl.InterpretedResponse]:
"""
Expand Down Expand Up @@ -238,8 +255,8 @@ def change_session(self, newsession: int) -> Optional[services.DiagnosticSession
if self.config['use_server_timing']:
self.logger.info('%s - Received new timing parameters. P2=%.3fs and P2*=%.3fs. Using these value from now on.' %
(self.service_log_prefix(services.DiagnosticSessionControl), response.service_data.p2_server_max, response.service_data.p2_star_server_max))
self.session_timing['p2_server_max'] = response.service_data.p2_server_max
self.session_timing['p2_star_server_max'] = response.service_data.p2_star_server_max
self.session_timing.p2_server_max = response.service_data.p2_server_max
self.session_timing.p2_star_server_max = response.service_data.p2_star_server_max

return response

Expand Down Expand Up @@ -2174,7 +2191,7 @@ def send_request(self, request: Request, timeout: int = -1) -> Optional[Response
if timeout < 0:
# Timeout not provided by user: defaults to Client request_timeout value
overall_timeout = self.config['request_timeout']
p2 = self.config['p2_timeout'] if self.session_timing['p2_server_max'] is None else self.session_timing['p2_server_max']
p2 = self.config['p2_timeout'] if self.session_timing.p2_server_max is None else self.session_timing.p2_server_max
if overall_timeout is not None:
single_request_timeout = min(overall_timeout, p2)
else:
Expand Down Expand Up @@ -2285,7 +2302,7 @@ def send_request(self, request: Request, timeout: int = -1) -> Optional[Response
done_receiving = False
if not using_p2_star:
# Received a 0x78 NRC: timeout is now set to P2*
p2_star = self.config['p2_star_timeout'] if self.session_timing['p2_star_server_max'] is None else self.session_timing['p2_star_server_max']
p2_star = self.config['p2_star_timeout'] if self.session_timing.p2_star_server_max is None else self.session_timing.p2_star_server_max
single_request_timeout = p2_star
using_p2_star = True
self.logger.debug("Server requested to wait with response code %s (0x%02x), single request timeout is now set to P2* (%.3f seconds)" %
Expand Down