42
42
43
43
44
44
# Constants needed for precise handling of timestamps
45
- RECEIVED_TIMESTAMP_STRUCT = struct .Struct ("@ll" )
45
+ RECEIVED_TIMESPEC_STRUCT = struct .Struct ("@ll" )
46
46
RECEIVED_ANCILLARY_BUFFER_SIZE = (
47
- CMSG_SPACE (RECEIVED_TIMESTAMP_STRUCT .size ) if CMSG_SPACE_available else 0
47
+ CMSG_SPACE (RECEIVED_TIMESPEC_STRUCT .size * 3 ) if CMSG_SPACE_available else 0
48
48
)
49
49
50
50
@@ -556,11 +556,26 @@ def capture_message(
556
556
# Fetching the timestamp
557
557
assert len (ancillary_data ) == 1 , "only requested a single extra field"
558
558
cmsg_level , cmsg_type , cmsg_data = ancillary_data [0 ]
559
- assert (
560
- cmsg_level == socket .SOL_SOCKET and cmsg_type == constants .SO_TIMESTAMPNS
559
+ assert cmsg_level == socket .SOL_SOCKET and (
560
+ (cmsg_type == constants .SO_TIMESTAMPNS )
561
+ or (cmsg_type == constants .SO_TIMESTAMPING )
561
562
), "received control message type that was not requested"
562
563
# see https://man7.org/linux/man-pages/man3/timespec.3.html -> struct timespec for details
563
- seconds , nanoseconds = RECEIVED_TIMESTAMP_STRUCT .unpack_from (cmsg_data )
564
+
565
+ if cmsg_type == constants .SO_TIMESTAMPNS :
566
+ seconds , nanoseconds = RECEIVED_TIMESPEC_STRUCT .unpack_from (cmsg_data )
567
+
568
+ if cmsg_type == constants .SO_TIMESTAMPING :
569
+ # stamp[0] is the software timestamp
570
+ # stamp[1] is deprecated
571
+ # stamp[2] is the raw hardware timestamp
572
+ # See chapter 2.1.2 Receive timestamps in
573
+ # linux/Documentation/networking/timestamping.txt
574
+ offset = struct .calcsize (RECEIVED_TIMESPEC_STRUCT .format ) * 2
575
+ seconds , nanoseconds = RECEIVED_TIMESPEC_STRUCT .unpack_from (
576
+ cmsg_data , offset = offset
577
+ )
578
+
564
579
if nanoseconds >= 1e9 :
565
580
raise can .CanOperationError (
566
581
f"Timestamp nanoseconds field was out of range: { nanoseconds } not less than 1e9"
@@ -619,6 +634,7 @@ def __init__(
619
634
self ,
620
635
channel : str = "" ,
621
636
receive_own_messages : bool = False ,
637
+ use_system_timestamp : bool = True ,
622
638
local_loopback : bool = True ,
623
639
fd : bool = False ,
624
640
can_filters : Optional [CanFilters ] = None ,
@@ -642,6 +658,9 @@ def __init__(
642
658
channel using :attr:`can.Message.channel`.
643
659
:param receive_own_messages:
644
660
If transmitted messages should also be received by this bus.
661
+ :param bool use_system_timestamp:
662
+ Use system timestamp for can messages instead of the hardware time
663
+ stamp
645
664
:param local_loopback:
646
665
If local loopback should be enabled on this bus.
647
666
Please note that local loopback does not mean that messages sent
@@ -659,6 +678,7 @@ def __init__(
659
678
self .socket = create_socket ()
660
679
self .channel = channel
661
680
self .channel_info = f"socketcan channel '{ channel } '"
681
+ self .use_system_timestamp = use_system_timestamp
662
682
self ._bcm_sockets : Dict [str , socket .socket ] = {}
663
683
self ._is_filtered = False
664
684
self ._task_id = 0
@@ -703,12 +723,25 @@ def __init__(
703
723
except OSError as error :
704
724
log .error ("Could not enable error frames (%s)" , error )
705
725
706
- # enable nanosecond resolution timestamping
707
- # we can always do this since
708
- # 1) it is guaranteed to be at least as precise as without
709
- # 2) it is available since Linux 2.6.22, and CAN support was only added afterward
710
- # so this is always supported by the kernel
711
- self .socket .setsockopt (socket .SOL_SOCKET , constants .SO_TIMESTAMPNS , 1 )
726
+ if self .use_system_timestamp :
727
+ # Utilise SOF_TIMESTAMPNS interface :
728
+ # we can always do this since
729
+ # 1) it is guaranteed to be at least as precise as without
730
+ # 2) it is available since Linux 2.6.22, and CAN support was only added afterward
731
+ # so this is always supported by the kernel
732
+ self .socket .setsockopt (socket .SOL_SOCKET , constants .SO_TIMESTAMPNS , 1 )
733
+ else :
734
+ # Utilise SOF_TIMESTAMPNS interface :
735
+ # Allows us to use hardware timestamps where available
736
+ timestamping_flags = (
737
+ constants .SOF_TIMESTAMPING_SOFTWARE
738
+ | constants .SOF_TIMESTAMPING_RX_SOFTWARE
739
+ | constants .SOF_TIMESTAMPING_RAW_HARDWARE
740
+ )
741
+
742
+ self .socket .setsockopt (
743
+ socket .SOL_SOCKET , constants .SO_TIMESTAMPING , timestamping_flags
744
+ )
712
745
713
746
try :
714
747
bind_socket (self .socket , channel )
0 commit comments