Skip to content

Commit 0c488bf

Browse files
committed
improve time stamp accuracy of the CAN messages for Kvaser and Vector buses on the Windows platform. (see hardbyte#934)
On Windows the value returned by time.time is refreshed at best every 0.5ms, and on some PCs the default refresh rate is every 10ms. The idea is to get the value of time.perf_counter at the moment when time.time is refreshed and use this as a reference point.
1 parent c2f6426 commit 0c488bf

File tree

3 files changed

+30
-3
lines changed

3 files changed

+30
-3
lines changed

can/interfaces/kvaser/canlib.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from can import CanError, BusABC
1515
from can import Message
16+
from can.util import time_perfcounter_correlation
1617
from . import constants as canstat
1718
from . import structures
1819

@@ -491,12 +492,16 @@ def __init__(self, channel, can_filters=None, **kwargs):
491492
canBusOn(self._write_handle)
492493

493494
timer = ctypes.c_uint(0)
495+
ts, perfcounter = time_perfcounter_correlation()
494496
try:
495497
kvReadTimer(self._read_handle, ctypes.byref(timer))
498+
current_perfcounter = time.perf_counter()
499+
now = ts + (current_perfcounter - perfcounter)
500+
self._timestamp_offset = now - (timer.value * TIMESTAMP_FACTOR)
496501
except Exception as exc:
497502
# timer is usually close to 0
498503
log.info(str(exc))
499-
self._timestamp_offset = time.time() - (timer.value * TIMESTAMP_FACTOR)
504+
self._timestamp_offset = time.time() - (timer.value * TIMESTAMP_FACTOR)
500505

501506
self._is_filtered = False
502507
super().__init__(channel=channel, can_filters=can_filters, **kwargs)

can/interfaces/vector/canlib.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
# Import Modules
3333
# ==============
3434
from can import BusABC, Message
35-
from can.util import len2dlc, dlc2len, deprecated_args_alias
35+
from can.util import len2dlc, dlc2len, deprecated_args_alias, time_perfcounter_correlation
3636
from .exceptions import VectorError
3737

3838
# Define Module Logger
@@ -295,11 +295,14 @@ def __init__(
295295
# Calculate time offset for absolute timestamps
296296
offset = xlclass.XLuint64()
297297
try:
298+
ts, perfcounter = time_perfcounter_correlation()
298299
try:
299300
xldriver.xlGetSyncTime(self.port_handle, offset)
300301
except VectorError:
301302
xldriver.xlGetChannelTime(self.port_handle, self.mask, offset)
302-
self._time_offset = time.time() - offset.value * 1e-9
303+
current_perfcounter = time.perf_counter()
304+
now = ts + (current_perfcounter - perfcounter)
305+
self._time_offset = now - offset.value * 1e-9
303306
except VectorError:
304307
self._time_offset = 0.0
305308

can/util.py

+19
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import functools
55
import warnings
66
from typing import Dict, Optional, Union
7+
from time import time, perf_counter
78

89
from can import typechecking
910

@@ -325,6 +326,24 @@ def rename_kwargs(func_name, kwargs, aliases):
325326
else:
326327
warnings.warn("{} is deprecated".format(alias), DeprecationWarning)
327328

329+
def time_perfcounter_correlation():
330+
""" on Windows platform this will help with the accuracy of using the time.time fucntion.
331+
332+
Returns
333+
-------
334+
t, performance_counter : (time.time, float)
335+
time.time value and perf_counter value when the time.time is updated
336+
337+
"""
338+
if platform.system() == "Windows":
339+
t0 = time()
340+
while 1:
341+
t1, performance_counter = time(), perf_counter()
342+
if t1 != t0:
343+
break
344+
else:
345+
return time(), perf_counter()
346+
return t1, performance_counter
328347

329348
if __name__ == "__main__":
330349
print("Searching for configuration named:")

0 commit comments

Comments
 (0)