Skip to content

M3: unified PTP–SMV context supervisor, continuous PPS↔smpCnt, dual clock authority and bounded recovery #162

Open

Description

@masarray

M3 — Smart, reliable, context-aware ESP32-P4 PTP–SMV runtime

Decision / release guard

M3 is NOT achieved yet. The current M1–M2F work is in Draft PR #153 and PR #157; the latter was at 90062f391a9c97cb1ff20d072b7f15ba4a777fac when scoped and diverged from main (77 ahead / 13 behind). The public SMV Injector baseline must not be silently replaced. This issue is the M3 implementation/acceptance contract, not a claim of finished firmware or IED acceptance.

Core nonnegotiable acceptance: smpCnt=0 must be causally tied to each correct logical PTP one-second boundary and its subsequent frame/sample cadence must remain continuously disciplined, not merely PTP-aligned once at START. Support (A) ESP32-P4 internal local PTP Grandmaster using its own oscillator as a truthful, untraceable time source, and (B) TIME_RECEIVER disciplined by external GPS/PTP GM. Neither task alone proves the peer IED is locked. A physical PPS pin is OPTIONAL test instrumentation; the mandatory reference is the EMAC PTP epoch/second boundary.

Current code audit / exact starting point

  • include/ariec61850/time_sync/sv_ptp_epoch.hpp plan_sv_ptp_second_arm() aligns the initial GPTimer alarm to the next EMAC PTP whole second. It explicitly does not discipline subsequent sample intervals.
  • embedded/esp32p4_smv_injector/main/app_main.cpp plan_source_ptp_epoch_arm() rejects every role except AR_PTP_ROLE_LAB_SOURCE; otherwise START can use the free-running rational GPTimer. For the 1-ASDU / 80-SPC profile where sample_counter_modulus == publisher_rate_hz, smpCnt=0 is the logical per-second epoch. Do not assume this invariant for arbitrary ASDU grouping, frequency or SCL profile.
  • sv_ptp_phase_authority.hpp plus app_main.cpp M2A has bounded 1Hz control-plane PI/slew for SOURCE, with explicit session/fault/source generation guards, but CONFIG_AR_SMV_PTP_PHASE_SERVO_EXPERIMENTAL defaults OFF. M2C/M2D sparse actual-SV descriptor timestamp evidence is opt-in and can perturb TX; it has no on-hardware success evidence yet.
  • ptp_receiver_task.cpp has external-Ptp SOURCE discovery, hardware Pdelay, frequency/phase EMAC clock discipline, timeout and holdover; it does not yet supply the same continuously qualified SV/GPTimer bridge as SOURCE.
  • smp_synch_lab.cpp in PR M2A: bounded continuous PTP–SMV phase authority and guarded ESP32-P4 observer #157 retains g_sv_timeline_phase_qualified=false without production promotion. This correctly avoids falsely asserting smpSynch=1/2, but the acceptance gate is unfinished.
  • live_control.cpp START sets running before publisher profile/template validation; publisher may log START rejection and continue without atomically reporting STOP/error. Require explicit START transaction acknowledgement from actual runtime.
  • sdkconfig.defaults still enables CONFIG_AR_SMV_BROADCAST_MIRROR=y; the normal interop profile must disable noncanonical mirror/probes unless explicitly requested.
  • M2F SOURCE freshness/TAI/UTC flag truthfulness is important: internal GM clockClass=248, unknown accuracy and nontraceable must not be spoofed to force IED lock.

Design contract: small, deterministic, no naive global state explosion

One single-writer, event-driven control-plane supervisor publishes a fixed-size immutable ContextSnapshot (atomic generation+snapshot handoff, or provably coherent bounded critical section). Separate orthogonal facts rather than one enormous branch tree:

  • ClockRole: LOCAL_GM | EXTERNAL_RECEIVER | MONITOR | OFF.
  • ClockEvidence: NOT_READY | ACQUIRING | LOCAL_READY | EXTERNAL_LOCKED | HOLDOVER | STALE | FAULT; include selected master identity, source/clock generation, offset uncertainty, time provenance and age.
  • SampleEvidence: STOPPED | ARMING | PHASE_ACQUIRING | PHASE_TRACKING | UNQUALIFIED | FAULT; include profile generation, epoch generation, planned alarm time, rational sample index, missed-slots and TX-fault generation, last observed phase, bounded uncertainty.
  • LinkHealth and ControlLease; explicit UserPolicy on whether bench-only unqualified/free-running SV is permitted.
  • Derive can_start, can_continue, can_assert_smpSynch, should_rearm from a pure policy engine with exhaustive portable truth-table tests. Every asynchronous result carries (session_id, source_generation, profile_generation); stale commands must be discarded.
  • Control plane owns role changes; PTP and SMV ISR never perform network IOCTL, logging, heap allocation, mutex waiting, free-running correction calculations or unbounded loops. Allow only O(1) constant-time tick/atomic work at 4000/4800 fps.

Milestones, in strict order

M3.0 — verified integration foundation (before a firmware refactor)

M3.1 — context authority and transactional lifecycle

  • Implement immutable PtpSvContextSnapshot, pure decide_ptp_sv_action(), event/transition table, role/session lease and source/profile generation, reason codes and bounded timestamps.
  • Make START a transaction: config/preflight -> link/clock policy -> profile/frame verification -> GPTimer armed -> publisher acknowledged. On failure: STOP/release, expose the real reason to Studio; no running=true ghost state.
  • Implement idempotent STOP, stale notification suppression, serialized teardown, bounded timeout and explicit BUSY/CLEANUP_PENDING, with exhaustive STOP/START concurrency tests.

M3.2 — PPS/second-boundary ↔ smpCnt continuous synchronization (highest technical priority)

  • Define SvSampleEpochPolicy from explicit SCL/profile semantics: ASDU per packet, fs, counter modulus, samples per nominal period and second-boundary relationship. Reject unsupported mappings instead of assuming modulus == fps universally.
  • For one-ASDU 80 samples/nominal cycle: 50Hz ×80 = 4000 samples/s, target smpCnt=0 at each PTP second; 60Hz ×80 = 4800 samples/s. For other ASDU modes use a correct profile-specific mapping.
  • On START, obtain bounded nonblocking cross-clock observation of EMAC hardware PTP clock and GPTimer, reject stale/step/unsupported time and arm the next safe second boundary. In EXTERNAL_RECEIVER require verified selected source + sufficiently stable discipline/lock; in LOCAL_GM require fresh local source, not GPS/UTC traceability.
  • Continue disciplining the GPTimer sample deadline against EMAC seconds for the entire run using the existing bounded phase PI/slew and rational fractional intervals. Sample n nominally corresponds to PTP_second_boundary + n*1e9/fs and smpCnt must correspond to that sample's scheduled epoch, not CPU wake time. Never advance or reset smpCnt spuriously merely to hide drift; missed slots remain visible and revoke phase qualification.
  • Handle 32-bit timer rollover (>71 minutes at 1 MHz), 16-bit counters/epoch generations, clock step/frequency changes, first-sample timing, PTP source change and arbitrary START/STOP. Timestamp each canonical SV egress only in sparse lab diagnostics; do NOT busy-wait on every SV frame or fake hardware evidence with software send time.
  • Test virtual clock multi-hour monotonic PPS/epoch coherence at 4000/4800 samples/s, rational tick error, rollover, ± phase error, injected offsets/drift and skew, lost slots, and source restart. Software-only numerical acceptance: exact correct smpCnt per profile and no unbounded correction/catch-up/bursts; phase/egress physical tolerances will be profile/standard-derived and must be measured on hardware, not invented.

M3.3 — symmetric internal GM and external GPS-GM paths

  • Reuse one time-authority-to-sample scheduler bridge for both roles; source-specific clock qualification belongs outside the shared servo. External RECEIVER drives EMAC clock; LOCAL_GM owns EMAC clock, announces its real local quality and responds Pdelay.
  • Select modes explicitly and supervise transitions. External source/GM change and holdover are not equivalent to local GM: no invisible failover/rogue GM on an energized process bus. Provide opt-in, configurable island fallback with delayed advertisement, safe re-arm and mandatory phase reacquisition. Strict IED may reject untraceable local GM; never falsify clockClass, timeTraceable, frequencyTraceable, ptpTimescale or UTC offset.
  • Preserve and verify PTP profile values: domain, transportSpecific, VLAN, Announce/Sync cadence, sourceIdentity, stepsRemoved, Pdelay request/response. Keep all adjustments off the hard realtime SV path.

M3.4 — evidence-driven smpSynch and receiver interop semantics

  • Create a separate qualifier taking PTP source/receiver evidence + SV planned phase continuity + bounded uncertainty + fault-free canonical frame history + freshness + matching session/generation.
  • In AUTO, smpSynch=0 until evidence passes; only then consider 1 for proven local synchronization domain and 2 for proven global synchronization per the relevant IEC 61850-9-2 / IEC 61869-9 mapping, not merely external GM lock. Revoke immediately on source loss, interval slip, clock step, TX loss or stale age. Lab force overrides must be visibly flagged and never accepted as measured.
  • Do not claim IED locked based only on ESP32's own SOURCE sending; only an independent receiver/bench observation can establish IED acceptance.

M3.5 — bounded recovery and context awareness

  • Inject Ethernet LINK_DOWN/UP, SOURCE stale, external GM disappeared/changed, clock step, unstable Pdelay, missed sample slots, TX 400-consecutive-failure stop, lease expiry, rapid START/STOP, receiver asynchronous cleanup.
  • Pure policy gives retryable | recoverable_rearm | requires_user_action reason; bounded debounce, limited backoff, retry budget and clean reset of source/session/servo. Never infinite recover/restart storm or a stale READY.
  • Explicit operational policy: Strict interop refuses qualified SMV before clock+phase qualification; optional Bench permissive permits TX with smpSynch=0 and a visible FREE_RUNNING/UNQUALIFIED status. Switching policy is explicit, not silent.
  • Distinguish transport STOP, PTP reacquisition and SV quality demotion. Do not restart a healthy publisher merely to update telemetry.

M3.6 — realtime performance, diagnostics and resource budget

  • Disable broadcast mirror and probe frames for production-shaped interop baseline; avoid unbounded shared EMAC lock contention between timestamped PTP TX and 4000/4800 SV fps. Instrument missed deadline, skipped slots, TX time, and bounded phase drift without per-frame allocation/log/IOCTL.
  • One low-rate aggregated telemetry snapshot with clockRole, clockState, selectedGM, PTPoffset, sourceAge, PPS/smpCnt phase, SV synchronization qualification, TX/missedSlots, recoveryReason, epochGeneration, and explicit UNKNOWN where instrumentation is absent. Studio must never show stale LOCKED.
  • Distinguish scheduled sample ISR phase, actual Ethernet MAC egress phase, protocol Sync frame hardware timestamp and IED receiver lock. These are not interchangeable.

M3.7 — deterministic acceptance / efficient CI / deployment gate

  • Portable unit tests: policy state table, timer/smpCnt/PPS math, 4000/4800Hz epochs, 32-bit rollover, SOURCE/RECEIVER symmetry, stale generation, clock jumps, holdover limits, sync promotion/revocation, bounded retry, single-writer snapshot consistency.
  • Independent wire/PCAP fixture for PTP Announce/Sync/FollowUp/Pdelay and SV smpCnt monotonic/wrap, APPID/VLAN/ASDU/sequence, quality/time semantics.
  • One lightweight portable CI on relevant changes. Run one explicit guarded ESP32-P4 SOURCE+RECEIVER compile only on checkpoints or ready-to-merge; do not rebuild Windows installer, unrelated Qt, or many matrices per micro-commit. Publish a smoke-test firmware artifact for physical trial at a clean milestone only.
  • Software PASS != hardware qualification. With no IED/GPS/PPS hardware available, deliver software evidence and an external capture checklist; keep release/merge gates explicit. Hardware acceptance later requires actual MAC timing/clock capture, IED lock/alarms and long-running 50/60Hz interop.

Invariants / prohibited shortcuts

  • One authority per session for PTP epoch and SV sample grid; conflicting SOURCE+RECEIVER role must not start.
  • Deterministic smpCnt follows scheduled sample index; never renumber past dropped samples as if nothing happened. A phase fault invalidates smpSynch immediately.
  • PTP READY means fresh evidence, not GPS traceability; PTP LOCKED alone does not imply SV qualified. No fake PPS/GPS, no fabricated TX timestamps, no hard-coded clock-quality promotions.
  • Never introduce a synchronous PTP ioctl, TX descriptor busy-wait, heap allocation, logging or unbounded loop into the 4000/4800Hz ISR.
  • No naive duplicated state machines or per-frame dynamic fallbacks. Use pure small algorithms, explicit profile contracts, immutable snapshots and narrow task ownership.
  • Do not merge Draft PR M1: standards-aligned PTP source defaults and fail-closed SV epoch startup #153/M2A: bounded continuous PTP–SMV phase authority and guarded ESP32-P4 observer #157 to main, auto-release, or change the public installer as a side effect of creating this plan.

Exit gate

M3 READY only once internal GM and external receiver share the verified continuous PPS/smpCnt phase bridge, clock changes cannot produce phantom RUNNING_QUALIFIED, fail-closed smpSynch is derived from proper evidence, bounded recovery/fault injection and realtime regression pass on the reconciled main baseline. Full interop/physical sign-off remains blocked until independent ESP32-P4/IED/GPS measurements become available.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions