2727 log .error ("fcntl not available on this platform" )
2828
2929
30+ try :
31+ from socket import CMSG_SPACE
32+
33+ CMSG_SPACE_available = True
34+ except ImportError :
35+ CMSG_SPACE_available = False
36+ log .error ("socket.CMSG_SPACE not available on this platform" )
37+
38+
3039import can
3140from can import Message , BusABC
3241from can .broadcastmanager import (
3847from can .interfaces .socketcan .constants import * # CAN_RAW, CAN_*_FLAG
3948from can .interfaces .socketcan .utils import pack_filters , find_available_interfaces
4049
50+
4151# Setup BCM struct
4252def bcm_header_factory (
4353 fields : List [Tuple [str , Union [Type [ctypes .c_uint32 ], Type [ctypes .c_long ]]]],
@@ -494,6 +504,8 @@ def bind_socket(sock: socket.socket, channel: str = "can0") -> None:
494504
495505 :param sock:
496506 The socket to be bound
507+ :param channel:
508+ The channel / interface to bind to
497509 :raises OSError:
498510 If the specified interface isn't found.
499511 """
@@ -517,24 +529,27 @@ def capture_message(
517529 """
518530 # Fetching the Arb ID, DLC and Data
519531 try :
532+ cf , ancillary_data , msg_flags , addr = sock .recvmsg (
533+ CANFD_MTU , RECEIVED_ANCILLARY_BUFFER_SIZE
534+ )
520535 if get_channel :
521- cf , _ , msg_flags , addr = sock .recvmsg (CANFD_MTU )
522536 channel = addr [0 ] if isinstance (addr , tuple ) else addr
523537 else :
524- cf , _ , msg_flags , _ = sock .recvmsg (CANFD_MTU )
525538 channel = None
526- except socket .error as exc :
527- raise can .CanError ("Error receiving: %s" % exc )
539+ except socket .error as error :
540+ raise can .CanError (f "Error receiving: { error } " )
528541
529542 can_id , can_dlc , flags , data = dissect_can_frame (cf )
530- # log.debug('Received: can_id=%x, can_dlc=%x, data=%s', can_id, can_dlc, data)
531543
532544 # Fetching the timestamp
533- binary_structure = "@LL"
534- res = fcntl .ioctl (sock .fileno (), SIOCGSTAMP , struct .pack (binary_structure , 0 , 0 ))
535-
536- seconds , microseconds = struct .unpack (binary_structure , res )
537- timestamp = seconds + microseconds * 1e-6
545+ assert len (ancillary_data ) == 1 , "only requested a single extra field"
546+ cmsg_level , cmsg_type , cmsg_data = ancillary_data [0 ]
547+ assert (
548+ cmsg_level == socket .SOL_SOCKET and cmsg_type == SO_TIMESTAMPNS
549+ ), "received control message type that was not requested"
550+ # see https://man7.org/linux/man-pages/man3/timespec.3.html -> struct timespec for details
551+ seconds , nanoseconds = RECEIVED_TIMESTAMP_STRUCT .unpack_from (cmsg_data )
552+ timestamp = seconds + nanoseconds * 1e-9
538553
539554 # EXT, RTR, ERR flags -> boolean attributes
540555 # /* special address description flags for the CAN_ID */
@@ -574,11 +589,15 @@ def capture_message(
574589 data = data ,
575590 )
576591
577- # log_rx.debug('Received: %s', msg)
578-
579592 return msg
580593
581594
595+ # Constants needed for precise handling of timestamps
596+ if CMSG_SPACE_available :
597+ RECEIVED_TIMESTAMP_STRUCT = struct .Struct ("@II" )
598+ RECEIVED_ANCILLARY_BUFFER_SIZE = CMSG_SPACE (RECEIVED_TIMESTAMP_STRUCT .size )
599+
600+
582601class SocketcanBus (BusABC ):
583602 """A SocketCAN interface to CAN.
584603
@@ -647,7 +666,7 @@ def __init__(
647666 except socket .error as error :
648667 log .error ("Could not receive own messages (%s)" , error )
649668
650- # enable CAN-FD frames
669+ # enable CAN-FD frames if desired
651670 if fd :
652671 try :
653672 self .socket .setsockopt (SOL_CAN_RAW , CAN_RAW_FD_FRAMES , 1 )
@@ -660,6 +679,13 @@ def __init__(
660679 except socket .error as error :
661680 log .error ("Could not enable error frames (%s)" , error )
662681
682+ # enable nanosecond resolution timestamping
683+ # we can always do this since
684+ # 1) is is guaranteed to be at least as precise as without
685+ # 2) it is available since Linux 2.6.22, and CAN support was only added afterward
686+ # so this is always supported by the kernel
687+ self .socket .setsockopt (socket .SOL_SOCKET , SO_TIMESTAMPNS , 1 )
688+
663689 bind_socket (self .socket , channel )
664690 kwargs .update (
665691 {
0 commit comments