diff --git a/python/fusion_engine_client/applications/p1_capture.py b/python/fusion_engine_client/applications/p1_capture.py index 24483866..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,8 +206,7 @@ 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) + 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 e977e28b..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] @@ -102,16 +102,51 @@ 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 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):