Skip to content

Commit c851cd1

Browse files
authored
Added configurable wait func (#108)
1 parent 4d15123 commit c851cd1

3 files changed

Lines changed: 40 additions & 1 deletion

File tree

doc/source/isotp/implementation.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,18 @@ The transport layer ``params`` parameter must be a dictionary with the following
252252

253253
Sets the name of the logger from the ``logging`` module used to log info and debug information
254254

255+
.. _param_wait_func:
256+
257+
.. attribute:: wait_func
258+
:annotation: (callable)
259+
260+
**default: "time.sleep"**
261+
262+
Defines a waiting function used to create the necessary delay between consecutive frames during a transmission, dictated by the receiver STMin.
263+
Expected signature is ``my_wait_func(delay:float) -> None``
264+
265+
Defaults value is the system ``sleep`` function, which can have a coarse granularity, depending on the scheduler policy.
266+
255267
-----
256268

257269
.. _rate_limiter_section:
@@ -407,6 +419,9 @@ Using the approach described above, a message can be read from the link-layer an
407419
40us latency is far better than the latency caused by calls to ``time.sleep()`` required with v1.x. Considering that a CAN bus running at 500kbps has a message duration of about 230us,
408420
the latency is in the acceptable range.
409421

422+
Finally, the delay between consecutive frames is dictated by a user-definable function passed with the :ref:`wait_func<param_wait_func>` parameter. By default, the wait function is the system ``sleep`` function.
423+
On machines where the ``sleep`` function has a coarse granularity and a high resolution timer is available, it is possible to pass a busy-wait function to this parameter.
424+
410425
--------
411426

412427
.. _backward_compatibility:

isotp/protocol.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ class Params:
321321
listen_mode: bool
322322
blocking_send: bool
323323
logger_name: str
324+
wait_func: Callable[[float], None]
324325

325326
def __init__(self):
326327
self.stmin = 0
@@ -342,6 +343,7 @@ def __init__(self):
342343
self.listen_mode = False
343344
self.blocking_send = False
344345
self.logger_name = TransportLayer.LOGGER_NAME
346+
self.wait_func = time.sleep
345347

346348
def set(self, key: str, val: Any, validate: bool = True) -> None:
347349
param_alias: Dict[str, str] = {
@@ -464,6 +466,14 @@ def validate(self) -> None:
464466
if not isinstance(self.logger_name, str):
465467
raise ValueError('logger_name must be a string')
466468

469+
if not callable(self.wait_func):
470+
raise ValueError('wait_func should be a callable')
471+
472+
try:
473+
self.wait_func(0.001)
474+
except Exception as e:
475+
raise ValueError("Given wait_func raised an exception %s" % e)
476+
467477
class RxState(enum.Enum):
468478
IDLE = 0
469479
WAIT_CF = 1
@@ -1557,7 +1567,7 @@ def _main_thread_fn(self) -> None:
15571567
delay = self.next_cf_delay()
15581568
assert delay is not None # Confirmed by is_tx_transmitting_cf()
15591569
if delay > 0:
1560-
time.sleep(delay) # If we are transmitting CFs, no need to call rxfn, we can stream those CF with short sleep
1570+
self.params.wait_func(delay) # If we are transmitting CFs, no need to call rxfn, we can stream those CF with short sleep
15611571
if not self.events.stop_requested.is_set():
15621572
super().process(do_rx=False, do_tx=True)
15631573
else:

test/test_transport_layer_logic.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,6 +1670,20 @@ def test_params_bad_values(self):
16701670
params['logger_name'] = 'asd'
16711671
self.create_layer(params)
16721672

1673+
for val in ['asd', 1.1, None]:
1674+
with self.assertRaises(ValueError):
1675+
params['wait_func'] = val
1676+
self.create_layer(params)
1677+
1678+
def wait_func_bad_signature():
1679+
pass
1680+
1681+
with self.assertRaises(ValueError):
1682+
params['wait_func'] = val
1683+
self.create_layer(params)
1684+
1685+
params['wait_func'] = time.sleep
1686+
16731687
# Check the behavior of the transport layer. Sequenece of CAN frames, timings, etc.
16741688

16751689

0 commit comments

Comments
 (0)