..
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************
.. _gptp_engine_design:
############################
gPTP Engine Design
############################
.. contents:: Table of Contents
:depth: 3
:local:
Overview
========
The ``GptpEngine`` is the core protocol engine of TimeSlave. It implements the IEEE 802.1AS
gPTP slave clock functionality by managing two dedicated threads for network I/O and peer
delay measurement.
Class view
==========
.. raw:: html
.. uml:: _assets/gptp_engine_class.puml
:alt: gPTP Engine Class Diagram
.. raw:: html
Threading model
===============
The GptpEngine operates with two background threads:
.. raw:: html
.. uml:: _assets/gptp_threading.puml
:alt: gPTP Engine Threading Model
.. raw:: html
RxThread
--------
The RxThread is the primary receive path. It runs a continuous loop:
1. **Recv** — Blocks on ``IRawSocket::Recv()`` with a configurable timeout, receiving raw
Ethernet frames with hardware timestamps from the NIC.
2. **Decode** — ``FrameCodec::ParseEthernetHeader()`` strips the Ethernet header (with VLAN
support) and validates the EtherType (``0x88F7``).
3. **Parse** — ``MessageParser::Parse()`` decodes the PTP payload into a ``PTPMessage``
structure, identifying the message type (Sync, FollowUp, PdelayResp, PdelayRespFollowUp).
4. **Dispatch** — Based on message type:
- **Sync** → ``SyncStateMachine::OnSync()`` stores the Sync timestamp
- **FollowUp** → ``SyncStateMachine::OnFollowUp()`` correlates with the preceding Sync,
computes ``offset_ns`` and ``neighborRateRatio``, and detects time jumps
- **PdelayResp** → ``PeerDelayMeasurer::OnResponse()``
- **PdelayRespFollowUp** → ``PeerDelayMeasurer::OnResponseFollowUp()``
5. **Snapshot** — After processing, the latest ``PtpTimeInfo`` snapshot is updated under
mutex protection.
PdelayThread
------------
The PdelayThread performs IEEE 802.1AS peer delay measurement on a periodic interval
(configurable via ``GptpEngineOptions::pdelay_interval_ms``):
1. **Send** — ``PeerDelayMeasurer::SendRequest()`` transmits a ``PDelayReq`` frame via the
raw socket, capturing the hardware transmit timestamp (``t1``).
2. **Receive** — The RxThread dispatches incoming ``PDelayResp`` (providing ``t2``) and
``PDelayRespFollowUp`` (providing ``t3c``) to the ``PeerDelayMeasurer``.
3. **Compute** — The peer delay is computed using the IEEE 802.1AS formula:
.. code-block:: text
path_delay = ((t2 - t1) + (t4 - t3c)) / 2
where ``t4`` is the local hardware receive timestamp of the PDelayResp frame.
Thread safety is ensured via a mutex in ``PeerDelayMeasurer``, as ``SendRequest()`` runs on
the PdelayThread while ``OnResponse()``/``OnResponseFollowUp()`` are called from the
RxThread.
Core components
===============
FrameCodec
----------
Handles raw Ethernet frame encoding and decoding:
- ``ParseEthernetHeader()`` — Parses source/destination MAC, handles 802.1Q VLAN tags,
extracts EtherType and payload offset.
- ``AddEthernetHeader()`` — Constructs Ethernet headers for outgoing PDelayReq frames using
the standard PTP multicast destination MAC (``01:80:C2:00:00:0E``).
MessageParser
-------------
Parses the PTP wire format (IEEE 1588-v2) from raw payload bytes:
- Validates the PTP header (version, domain, message length).
- Decodes message-type-specific bodies: ``SyncBody``, ``FollowUpBody``, ``PdelayReqBody``,
``PdelayRespBody``, ``PdelayRespFollowUpBody``.
- All wire structures are packed (``__attribute__((packed))``) for direct memory mapping.
SyncStateMachine
----------------
Implements the two-step Sync/FollowUp correlation logic:
- **OnSync(msg)** — Stores the Sync message and its hardware receive timestamp.
- **OnFollowUp(msg)** — Matches with the preceding Sync by sequence ID, then computes:
- ``offset_ns`` = master_time - slave_receive_time - path_delay
- ``neighborRateRatio`` from successive Sync intervals (master vs. slave clock progression)
- Time jump detection (forward/backward) against configurable thresholds
- **Timeout detection** — Uses ``std::atomic`` for thread-safe timeout status,
set when no Sync is received within ``sync_timeout_ms``.
PeerDelayMeasurer
-----------------
Implements the IEEE 802.1AS two-step peer delay measurement protocol:
- Manages the four timestamps (``t1``, ``t2``, ``t3c``, ``t4``) across two threads.
- ``SendRequest()`` — Builds and sends a PDelayReq frame, records ``t1`` from the
hardware transmit timestamp.
- ``OnResponse()`` / ``OnResponseFollowUp()`` — Records ``t2``, ``t3c``, ``t4`` and
computes the path delay when all timestamps are available.
- Returns ``PDelayResult`` with ``path_delay_ns`` and a ``valid`` flag.
PhcAdjuster
-----------
Synchronizes the PTP Hardware Clock (PHC) on the NIC:
- **Step correction** — For large offsets exceeding ``step_threshold_ns``, applies an
immediate time step to the PHC.
- **Frequency slew** — For smaller offsets, adjusts the clock frequency (in ppb) for
smooth convergence.
- Platform-specific: Linux uses ``clock_adjtime()``, QNX uses EMAC PTP ioctls.
- Configured via ``PhcConfig`` (device path, step threshold, enable/disable flag).
Instrumentation
===============
ProbeManager
------------
A singleton that records probe events at key processing points. Probe points include:
- ``RxPacketReceived`` — Raw frame received from socket
- ``SyncFrameParsed`` — Sync message successfully parsed
- ``FollowUpProcessed`` — Offset computed from Sync/FollowUp pair
- ``OffsetComputed`` — Final offset value available
- ``PdelayReqSent`` — PDelayReq frame transmitted
- ``PdelayCompleted`` — Peer delay measurement completed
- ``PhcAdjusted`` — PHC adjustment applied
The ``GPTP_PROBE()`` macro provides zero-overhead when probing is disabled.
Recorder
--------
Thread-safe CSV file writer that persists probe events and other diagnostic data. Each
``RecordEntry`` contains a timestamp, event type, offset, peer delay, sequence ID, and
status flags.
Configuration
=============
The ``GptpEngineOptions`` struct provides all configurable parameters:
.. list-table::
:header-rows: 1
:widths: 30 15 55
* - Parameter
- Type
- Description
* - ``interface_name``
- string
- Network interface for gPTP frames (e.g., ``eth0``)
* - ``pdelay_interval_ms``
- uint32_t
- Interval between PDelayReq transmissions
* - ``sync_timeout_ms``
- uint32_t
- Timeout for Sync message reception before declaring timeout state
* - ``time_jump_forward_ns``
- int64_t
- Threshold for forward time jump detection
* - ``time_jump_backward_ns``
- int64_t
- Threshold for backward time jump detection
* - ``phc_config``
- PhcConfig
- PHC device path, step threshold, and enable flag