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
@@ -557,10 +557,24 @@ def capture_message(
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
559
assert (
560
- cmsg_level == socket .SOL_SOCKET and cmsg_type == constants .SO_TIMESTAMPNS
560
+ cmsg_level == socket .SOL_SOCKET and (
561
+ (cmsg_type == constants .SO_TIMESTAMPNS ) or
562
+ (cmsg_type == constants .SO_TIMESTAMPING ))
561
563
), "received control message type that was not requested"
562
564
# 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 )
565
+
566
+ if cmsg_type == constants .SO_TIMESTAMPNS :
567
+ seconds , nanoseconds = RECEIVED_TIMESPEC_STRUCT .unpack_from (cmsg_data )
568
+
569
+ if cmsg_type == constants .SO_TIMESTAMPING :
570
+ # stamp[0] is the software timestamp
571
+ # stamp[1] is deprecated
572
+ # stamp[2] is the raw hardware timestamp
573
+ # See chapter 2.1.2 Receive timestamps in
574
+ # linux/Documentation/networking/timestamping.txt
575
+ offset = struct .calcsize (RECEIVED_TIMESPEC_STRUCT .format ) * 2
576
+ seconds , nanoseconds = RECEIVED_TIMESPEC_STRUCT .unpack_from (cmsg_data , offset = offset )
577
+
564
578
if nanoseconds >= 1e9 :
565
579
raise can .CanOperationError (
566
580
f"Timestamp nanoseconds field was out of range: { nanoseconds } not less than 1e9"
@@ -619,6 +633,7 @@ def __init__(
619
633
self ,
620
634
channel : str = "" ,
621
635
receive_own_messages : bool = False ,
636
+ use_system_timestamp : bool = True ,
622
637
local_loopback : bool = True ,
623
638
fd : bool = False ,
624
639
can_filters : Optional [CanFilters ] = None ,
@@ -642,6 +657,9 @@ def __init__(
642
657
channel using :attr:`can.Message.channel`.
643
658
:param receive_own_messages:
644
659
If transmitted messages should also be received by this bus.
660
+ :param bool use_system_timestamp:
661
+ Use system timestamp for can messages instead of the hardware time
662
+ stamp
645
663
:param local_loopback:
646
664
If local loopback should be enabled on this bus.
647
665
Please note that local loopback does not mean that messages sent
@@ -659,6 +677,7 @@ def __init__(
659
677
self .socket = create_socket ()
660
678
self .channel = channel
661
679
self .channel_info = f"socketcan channel '{ channel } '"
680
+ self .use_system_timestamp = use_system_timestamp
662
681
self ._bcm_sockets : Dict [str , socket .socket ] = {}
663
682
self ._is_filtered = False
664
683
self ._task_id = 0
@@ -703,12 +722,21 @@ def __init__(
703
722
except OSError as error :
704
723
log .error ("Could not enable error frames (%s)" , error )
705
724
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 )
725
+ if self .use_system_timestamp :
726
+ # Utilise SOF_TIMESTAMPNS interface :
727
+ # we can always do this since
728
+ # 1) it is guaranteed to be at least as precise as without
729
+ # 2) it is available since Linux 2.6.22, and CAN support was only added afterward
730
+ # so this is always supported by the kernel
731
+ self .socket .setsockopt (socket .SOL_SOCKET , constants .SO_TIMESTAMPNS , 1 )
732
+ else :
733
+ # Utilise SOF_TIMESTAMPNS interface :
734
+ # Allows us to use hardware timestamps where available
735
+ timestamping_flags = (constants .SOF_TIMESTAMPING_SOFTWARE |
736
+ constants .SOF_TIMESTAMPING_RX_SOFTWARE |
737
+ constants .SOF_TIMESTAMPING_RAW_HARDWARE )
738
+
739
+ self .socket .setsockopt (socket .SOL_SOCKET , constants .SO_TIMESTAMPING , timestamping_flags )
712
740
713
741
try :
714
742
bind_socket (self .socket , channel )
0 commit comments