Repository navigation
M3: unified PTP–SMV context supervisor, continuous PPS↔smpCnt, dual clock authority and bounded recovery #162
Description
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.hppplan_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.cppplan_source_ptp_epoch_arm()rejects every role exceptAR_PTP_ROLE_LAB_SOURCE; otherwise START can use the free-running rational GPTimer. For the 1-ASDU / 80-SPC profile wheresample_counter_modulus == publisher_rate_hz,smpCnt=0is the logical per-second epoch. Do not assume this invariant for arbitrary ASDU grouping, frequency or SCL profile.sv_ptp_phase_authority.hppplusapp_main.cppM2A has bounded 1Hz control-plane PI/slew for SOURCE, with explicit session/fault/source generation guards, butCONFIG_AR_SMV_PTP_PHASE_SERVO_EXPERIMENTALdefaults 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.cpphas 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.cppin PR M2A: bounded continuous PTP–SMV phase authority and guarded ESP32-P4 observer #157 retainsg_sv_timeline_phase_qualified=falsewithout production promotion. This correctly avoids falsely assertingsmpSynch=1/2, but the acceptance gate is unfinished.live_control.cppSTART sets running before publisher profile/template validation; publisher may log START rejection andcontinuewithout atomically reporting STOP/error. Require explicit START transaction acknowledgement from actual runtime.sdkconfig.defaultsstill enablesCONFIG_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.LinkHealthandControlLease; explicitUserPolicyon whether bench-only unqualified/free-running SV is permitted.- Derive
can_start,can_continue,can_assert_smpSynch,should_rearmfrom 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)
- Checkpoint exact tested M1–M2F branch heads + main. Reconcile 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 with current
mainwithout replacing GUI/installer or losing hardened TX/STOP safeguards. Keep one reviewable integration branch, no force-push over another worker's state. - Portable test + one explicit ESP32-P4 SOURCE and RECEIVER build on the integrated tree, not only on a stale branch; resolve genuine regressions first. Record baseline hashes and selected CI artifacts.
- All new features feature-gated, not automatically merged/released. Target CI changes only in relevant paths. Never retrigger the entire Studio/installer/release pipeline on a Draft push.
M3.1 — context authority and transactional lifecycle
- Implement immutable
PtpSvContextSnapshot, puredecide_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=trueghost 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
SvSampleEpochPolicyfrom explicit SCL/profile semantics: ASDU per packet, fs, counter modulus, samples per nominal period and second-boundary relationship. Reject unsupported mappings instead of assumingmodulus == fpsuniversally. - For one-ASDU 80 samples/nominal cycle: 50Hz ×80 = 4000 samples/s, target
smpCnt=0at 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
nnominally corresponds toPTP_second_boundary + n*1e9/fsandsmpCntmust correspond to that sample's scheduled epoch, not CPU wake time. Never advance or resetsmpCntspuriously 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
smpCntper 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,ptpTimescaleor 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=0until evidence passes; only then consider1for proven local synchronization domain and2for 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_actionreason; bounded debounce, limited backoff, retry budget and clean reset of source/session/servo. Never infinite recover/restart storm or a staleREADY. - Explicit operational policy: Strict interop refuses qualified SMV before clock+phase qualification; optional Bench permissive permits TX with
smpSynch=0and a visibleFREE_RUNNING/UNQUALIFIEDstatus. 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 explicitUNKNOWNwhere 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
smpCntmonotonic/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
smpCntfollows scheduled sample index; never renumber past dropped samples as if nothing happened. A phase fault invalidates smpSynch immediately. - PTP
READYmeans fresh evidence, not GPS traceability; PTPLOCKEDalone 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