Skip to content

PTP-P1: portable PTPv2 core and ESP32-P4 hardware-timestamped lab broadcaster - #62

Merged
masarray merged 39 commits into
mainfrom
feature/ptp-p1-core-port
Aug 11, 2026
Merged

masarray merged 39 commits into
mainfrom
feature/ptp-p1-core-port

Conversation

@masarray

@masarray masarray commented Aug 11, 2026 •

Copy link
Copy Markdown
Owner

Purpose

Port the ARIEC61850/ARSVIN laboratory PTP stack to the C++ ARStack core and establish the ESP32-P4 timing path needed for SMV troubleshooting/interoperability when a station GPS/PTP server is not yet available.

This is intentionally not a GPS-backed or certified grandmaster. The product role is a lab/field timing companion that can temporarily close the process-bus test gap when a relay requires PTP before it will accept/read Sampled Values.

The same portable C++ PTP core is also the foundation for the future PTP/SMV Analyzer.

PTP-P1 scope implemented

Portable C++ core

  • PTPv2 Layer-2 EtherType 0x88F7
  • Announce
  • Sync / Follow_Up
  • Pdelay_Req encoding
  • Pdelay_Resp / Pdelay_Resp_Follow_Up
  • transportSpecific encode/decode and evidence tracking
  • VLAN and QinQ parsing
  • general and peer-delay multicast recognition
  • passive source/domain/message monitor
  • sequence anomaly tracking
  • transportSpecific mismatch/change diagnostics
  • conservative PTP health / smpSynch policy primitives
  • read-only ariec61850_ptp_analyze PCAP CLI
  • analyzer filters for expected domain and expected transportSpecific
  • C#-oracle golden regression tests
  • fail-safe default smpSynch=0

ESP32-P4 lab timing companion

PTP remains default OFF and is enabled explicitly with CONFIG_AR_PTP_LAB_TX=y.

  • isolated CPU0 PTP task; existing realtime SMV publisher remains on CPU1
  • ESP32-P4 IEEE1588 hardware clock enabled through the ESP-IDF 5.x adapter
  • configurable domain and transportSpecific
  • optional configurable IEEE 802.1Q PTP VLAN / VID / PCP
  • conservative Announce clock quality: class 248 / unknown accuracy / 0xFFFF variance / internal oscillator
  • two-step Sync:
    • Sync carries zero originTimestamp with two-step flag
    • EMAC descriptor TX timestamp is captured
    • Follow_Up carries the actual Sync TX timestamp
  • hardware-timestamped peer delay:
    • timestamp-aware Ethernet RX callback receives the Pdelay_Req descriptor timestamp (t2)
    • Pdelay_Resp carries t2
    • Pdelay_Resp TX descriptor timestamp is captured (t3)
    • Pdelay_Resp_Follow_Up carries t3
    • request sequence ID, requestingPortIdentity and logMessageInterval are preserved
    • Pdelay request must match configured domain and transportSpecific

Analyzer direction

The portable parser/monitor is intentionally independent of ESP-IDF and desktop capture libraries. The PCAP CLI already exercises the read-only analyzer direction, and the same core can be reused by a future live ESP32-P4 PTP/SMV analyzer.

The analyzer reports domain, source identity, transportSpecific, VLAN/QinQ visibility, Announce/Sync/Follow_Up/Pdelay counts, sequence anomalies and transportSpecific stability. This directly supports diagnosis of cases where PTP is visible in Wireshark but a strict relay ignores it because profile/network identity differs.

Current ESP32 RX ownership is suitable for the standalone raw-L2 injector. A future combined analyzer should introduce one shared RX dispatcher rather than competing Ethernet input callbacks.

Validation gates

Dedicated CI covers:

  • strict GCC C++20 PTP build/tests (-Werror)
  • strict Clang C++20 PTP build/tests (-Werror)
  • standalone strict MSVC PTP core + analyzer profile (/W4 /WX)
  • default ESP32-P4 SMV firmware with PTP OFF
  • ESP32-P4 PTP-enabled firmware on ESP-IDF 5.5.4
  • non-default ESP32-P4 PTP profile with transportSpecific=1, VLAN 100 and PCP 4 so configurable bindings are compiled rather than left as dead configuration paths

The hardware-timestamped Sync and hardware RX/TX Pdelay paths compile in the ESP32-P4 PTP-enabled profile.

smpSynch boundary

PTP traffic visibility is not treated as proof that the SV sampling clock is disciplined.

PTP-P1 therefore does not automatically promote canonical SMV smpSynch merely because the local PTP broadcaster is running. Automatic smpSynch promotion remains reserved for a later measured lock/holdover model.

Deliberately deferred

  • physical relay lock/acceptance evidence
  • utility-profile-specific claim/configuration beyond sourced evidence
  • calibrated absolute UTC / GPS traceability
  • BMCA conformance claim
  • peer-delay/offset servo for disciplining the local clock to an external source
  • phase/frequency servo
  • lock / holdover / unlocked state machine
  • measured jitter/offset qualification
  • automatic smpSynch=1/2
  • formal IEC/IEEE 61850-9-3 conformance claims

Bench acceptance next

docs/PTP_LAB_TIMING.md defines the physical runbook. The first relay test should retain evidence for:

  1. Announce + Sync + matching Follow_Up visibility;
  2. expected domain / transportSpecific / VLAN binding;
  3. non-zero progressing hardware TX timestamps;
  4. relay Pdelay_Req followed by matching Pdelay_Resp + Pdelay_Resp_Follow_Up with hardware t2/t3;
  5. relay timing-ready/lock behavior;
  6. whether SMV becomes readable/usable;
  7. no regression in SMV rate, TX failures or missed slots.

The PR remains draft until the software CI gates are clean. Physical interoperability is a separate acceptance step.

@masarray
masarray marked this pull request as ready for review August 11, 2026 12:12
@masarray
masarray merged commit e7742eb into main Aug 11, 2026
19 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ec760427e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/time_sync/ptp.cpp
Comment on lines +163 to +164
std::vector<std::uint8_t> PtpCodec::build_pdelay_req(const PtpBuildOptions& options) {
return build_timestamp_message(PtpMessageType::pdelay_req, options, 0x05U);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Append the reserved tail to Pdelay_Req

When build_pdelay_req() is used, it emits only the 10-byte origin timestamp, producing a 44-byte message. A PTPv2 Pdelay_Req also requires a 10-byte reserved field and therefore has a 54-byte message length; conforming peers can discard the current encoding instead of participating in peer delay.

Useful? React with 👍 / 👎.

Comment on lines +367 to +371
if (report.is_healthy()) {
return SmpSynchValue::global_synchronized;
}
if (allow_local_fallback && report.snapshot.has_ptp()) {
return SmpSynchValue::local_synchronized;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep packet visibility from promoting smpSynch

When a caller uses this resolver to populate an SV ASDU, a healthy report proves only recent packet visibility, domain/profile matching, and message counts—not that the sampling clock is disciplined—yet it returns global_synchronized; even a report that failed liveness becomes local_synchronized by default as long as any historical PTP packet exists. This can publish a false synchronization claim, so promotion should require explicit measured lock/holdover state rather than passive-monitor health.

Useful? React with 👍 / 👎.

Comment on lines +89 to +92
config AR_PTP_VLAN_ID
int "PTP VLAN ID"
range 0 4095
default 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject reserved VLAN ID 4095 in configuration

When CONFIG_AR_PTP_VLAN_ID=4095, Kconfig accepts the value and the PTP codec also lets it through, but VlanTag::to_tag_control_information() rejects IDs above 4094 and throws during frame encoding. With tagged PTP enabled, this permitted configuration can terminate the PTP task before it transmits traffic; constrain the option to 0..4094.

Useful? React with 👍 / 👎.

Comment on lines +32 to +37
const auto message_count = source.count(type);
if (message_count != 0U) {
checks.push_back({
std::move(id),
PtpHealthSeverity::ok,
std::move(label) + " messages are visible from " + port_identity_text(source.source_port_identity) + ".",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Limit message-presence checks to the liveness window

When Sync/Follow_Up transmission stops but another message such as Announce continues, the source remains active while these lifetime counters stay nonzero, so the analyzer reports Sync and Follow_Up as healthy indefinitely. Presence checks need per-message timestamps or counts restricted to source_timeout; otherwise a capture containing an old successful exchange can conceal a current timing failure.

Useful? React with 👍 / 👎.

Comment on lines +329 to +330
if (options.require_follow_up_for_two_step) {
add_presence_check(checks, *selected, PtpMessageType::follow_up, "ptp.followup", "Follow_Up");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require Follow_Up only for two-step Sync

For a valid one-step PTP source, Sync carries its timestamp and no Follow_Up is sent, but the default analyzer unconditionally runs this failure-producing presence check. Consequently ordinary one-step captures are reported unhealthy despite the option being named require_follow_up_for_two_step; track whether the selected source's Sync is two-step before requiring Follow_Up.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant