4242
4343
4444# Constants needed for precise handling of timestamps
45- RECEIVED_TIMESTAMP_STRUCT = struct .Struct ("@ll" )
45+ RECEIVED_TIMESPEC_STRUCT = struct .Struct ("@ll" )
4646RECEIVED_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
4848)
4949
5050
@@ -556,11 +556,26 @@ def capture_message(
556556 # Fetching the timestamp
557557 assert len (ancillary_data ) == 1 , "only requested a single extra field"
558558 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 )
561562 ), "received control message type that was not requested"
562563 # 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+
564579 if nanoseconds >= 1e9 :
565580 raise can .CanOperationError (
566581 f"Timestamp nanoseconds field was out of range: { nanoseconds } not less than 1e9"
@@ -619,6 +634,7 @@ def __init__(
619634 self ,
620635 channel : str = "" ,
621636 receive_own_messages : bool = False ,
637+ use_system_timestamp : bool = True ,
622638 local_loopback : bool = True ,
623639 fd : bool = False ,
624640 can_filters : Optional [CanFilters ] = None ,
@@ -642,6 +658,9 @@ def __init__(
642658 channel using :attr:`can.Message.channel`.
643659 :param receive_own_messages:
644660 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
645664 :param local_loopback:
646665 If local loopback should be enabled on this bus.
647666 Please note that local loopback does not mean that messages sent
@@ -659,6 +678,7 @@ def __init__(
659678 self .socket = create_socket ()
660679 self .channel = channel
661680 self .channel_info = f"socketcan channel '{ channel } '"
681+ self .use_system_timestamp = use_system_timestamp
662682 self ._bcm_sockets : Dict [str , socket .socket ] = {}
663683 self ._is_filtered = False
664684 self ._task_id = 0
@@ -703,12 +723,25 @@ def __init__(
703723 except OSError as error :
704724 log .error ("Could not enable error frames (%s)" , error )
705725
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+ )
712745
713746 try :
714747 bind_socket (self .socket , channel )
0 commit comments