From 4b501e7353b0a5e8592b9dc0d1c01d680a0d4a91 Mon Sep 17 00:00:00 2001 From: Adam Shapiro Date: Fri, 7 Nov 2025 18:55:32 -0500 Subject: [PATCH 1/3] Fixed p1_capture socket recv call in Windows. recvmsg() and kernel timestamping is not supported in Windows. --- python/fusion_engine_client/applications/p1_capture.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/python/fusion_engine_client/applications/p1_capture.py b/python/fusion_engine_client/applications/p1_capture.py index 24483866..0eda5808 100755 --- a/python/fusion_engine_client/applications/p1_capture.py +++ b/python/fusion_engine_client/applications/p1_capture.py @@ -206,8 +206,11 @@ def _print_status(now): if isinstance(transport, socket.socket): ready = select.select([transport], [], [], read_timeout_sec) if ready[0]: - received_data, ancdata, _, _ = transport.recvmsg(1024, 1024) - kernel_ts, _, hw_ts = parse_timestamps_from_ancdata(ancdata) + if sys.platform == "linux": + received_data, ancdata, _, _ = transport.recvmsg(1024, 1024) + kernel_ts, _, hw_ts = parse_timestamps_from_ancdata(ancdata) + else: + received_data = transport.recv(1024) else: received_data = [] # If this is a serial port, we set the read timeout above. From ffceb0032155c1ffd0ddd3d8144272b7d7873131 Mon Sep 17 00:00:00 2001 From: Adam Shapiro Date: Thu, 13 Nov 2025 14:27:48 -0500 Subject: [PATCH 2/3] Don't try to enable socket timestamping on Windows. --- .../utils/socket_timestamping.py | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/python/fusion_engine_client/utils/socket_timestamping.py b/python/fusion_engine_client/utils/socket_timestamping.py index e977e28b..57445b1a 100755 --- a/python/fusion_engine_client/utils/socket_timestamping.py +++ b/python/fusion_engine_client/utils/socket_timestamping.py @@ -102,16 +102,29 @@ def parse_timestamps_from_ancdata(ancdata: list[_CMSG]) -> tuple[Optional[float] return tuple(timestamps) -def enable_socket_timestamping(sock: socket.socket, enable_sw_timestamp: bool, enable_hw_timestamp: bool): - if enable_sw_timestamp or enable_hw_timestamp: - flags = 0 - if enable_sw_timestamp: - flags |= SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE +def enable_socket_timestamping(sock: socket.socket, enable_sw_timestamp: bool, enable_hw_timestamp: bool) -> bool: + '''! + Enable kernel-level hardware or software timestamping of incoming socket data. - if enable_hw_timestamp: - flags |= SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE + @param sock The socket to be used. + @param enable_sw_timestamp Set to `True` to enable software timestamping in the kernel. + @param enable_hw_timestamp Set to `True` to enable hardware timestamping by the network interface. - sock.setsockopt(socket.SOL_SOCKET, SO_TIMESTAMPING, flags) + @return `True` if timestamping is supported on the host OS. + ''' + if sys.platform == "linux": + if enable_sw_timestamp or enable_hw_timestamp: + flags = 0 + if enable_sw_timestamp: + flags |= SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE + + if enable_hw_timestamp: + flags |= SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE + + sock.setsockopt(socket.SOL_SOCKET, SO_TIMESTAMPING, flags) + return True + else: + return False def log_timestamped_data_offset(fd: BinaryIO, timestamp_ns: int, byte_offset: int): From b768f566340a5a92bc69662156e6b2a53368ed30 Mon Sep 17 00:00:00 2001 From: Adam Shapiro Date: Thu, 13 Nov 2025 14:28:07 -0500 Subject: [PATCH 3/3] Added recv() helper to abstract socket timestamping details. --- .../applications/p1_capture.py | 8 ++----- .../utils/socket_timestamping.py | 24 ++++++++++++++++++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/python/fusion_engine_client/applications/p1_capture.py b/python/fusion_engine_client/applications/p1_capture.py index 0eda5808..75cf0732 100755 --- a/python/fusion_engine_client/applications/p1_capture.py +++ b/python/fusion_engine_client/applications/p1_capture.py @@ -22,7 +22,7 @@ from ..utils.socket_timestamping import (enable_socket_timestamping, HW_TIMESTAMPING_HELP, log_timestamped_data_offset, - parse_timestamps_from_ancdata, + recv, TIMESTAMP_FILE_ENDING,) from ..utils.transport_utils import * from ..utils.trace import HighlightFormatter, BrokenPipeStreamHandler @@ -206,11 +206,7 @@ def _print_status(now): if isinstance(transport, socket.socket): ready = select.select([transport], [], [], read_timeout_sec) if ready[0]: - if sys.platform == "linux": - received_data, ancdata, _, _ = transport.recvmsg(1024, 1024) - kernel_ts, _, hw_ts = parse_timestamps_from_ancdata(ancdata) - else: - received_data = transport.recv(1024) + received_data, kernel_ts, hw_ts = recv(transport, 1024) else: received_data = [] # If this is a serial port, we set the read timeout above. diff --git a/python/fusion_engine_client/utils/socket_timestamping.py b/python/fusion_engine_client/utils/socket_timestamping.py index 57445b1a..7e6a2923 100755 --- a/python/fusion_engine_client/utils/socket_timestamping.py +++ b/python/fusion_engine_client/utils/socket_timestamping.py @@ -11,7 +11,7 @@ import socket import struct import sys -from typing import BinaryIO, Optional, TypeAlias +from typing import BinaryIO, Optional, Tuple, TypeAlias _CMSG: TypeAlias = tuple[int, int, bytes] @@ -127,6 +127,28 @@ def enable_socket_timestamping(sock: socket.socket, enable_sw_timestamp: bool, e return False +def recv(sock: socket.socket, buffer_size: int) -> Tuple[bytes, Optional[float], Optional[float]]: + '''! + Receive data from the specified socket and capture timestamps, if enabled. + + @param sock The socket to be used. + @param buffer_size The maximum number of bytes to read. + + @return A tuple containing: + - The bytes read from the socket + - The kernel timestamp, if enabled + - The hardware timestamp, if enabled + ''' + if sys.platform == "linux": + received_data, ancdata, _, _ = sock.recvmsg(buffer_size, 1024) + kernel_ts, _, hw_ts = parse_timestamps_from_ancdata(ancdata) + else: + received_data = sock.recv(buffer_size) + kernel_ts = None + hw_ts = None + return received_data, kernel_ts, hw_ts + + def log_timestamped_data_offset(fd: BinaryIO, timestamp_ns: int, byte_offset: int): ''' Log the host timestamp associated with the reception of the byte at byte_offset.