All notable changes to the norxs Deterministic TSN Zonal Backbone are documented here. This project follows Semantic Versioning.
(Changes staged for the next release go here)
- OBS-001 (Medium): The gPTP convergence watchdog could never fire in slave
mode before the first sync, because
Tick()derived time exclusively from the PHC, which is unreadable inkFreeRun. The orchestrator now maintains a PHC-independent monotonic clock derived from theTick()period contract (monotonicNs_ += tickPeriodUs × 1000per tick) and drives the convergence watchdog from it. A slave that never receives Sync now correctly enterskFaultwithkPtpNotSynchronisedafterptpConvergenceTimeoutMs. Regression tests:OrchTest.Tick_SlaveNeverSyncs_ConvergenceWatchdogEntersFault,OrchTest.Tick_GrandmasterLocksBeforeTimeout_NoSpuriousFault. - OBS-002 (Low):
ScheduleParams::entryCountwidenedu8→u16so the documented [1, 256] range — and the full SJA1110/88Q5050 GCL SRAM depth — is representable. All iteration variables widened accordingly. API change (struct layout) — hence the minor version bump per SemVer. Regression tests:OrchTest.Init_Full256EntryGcl_PassesPrevalidation,OrchTest.Init_EntryCountAboveMax_RejectedAsGclEmpty.
- The FSM documentation promised
kDegraded → kSafeStatewhen the ASIL-D deadline can no longer be guaranteed, but no code path ever setkFaultNcDeadline— the safe state was unreachable. Implemented: if the hardware-schedule integrity fault (VerifyHardwareSchedule()mismatch) persists while degraded, the Network Calculus guarantees proven against the validated schedule are void for the operative GCL, so the orchestrator escalates tokSafeStatewith triggerkDeadlineViolationand re-applies the TC7-exclusive safe-state schedule on all ports. Tests:OrchTest.Tick_PersistentGclIntegrityFault_EscalatesToSafeState,OrchTest.AuditLog_SafeStateEntry_RecordsDeadlineViolationTrigger.
- Phase 0 configuration validation in
Init(): rejectstickPeriodUs == 0(would disable the monotonic watchdog) andschedulePortCount > kMaxSwitchPortswithkInvalidArgument, before any hardware is touched. - 5 holdover runtime-path tests (
PtpTest): sync-silence → holdover entry, TCXO drift-compensation PHC writes, budget expiry →kFreeRun+kPtpHoldoverExpired, 10× GM-silence detection, and re-sync recovery — previously a fully uncovered ASIL-D continuity mechanism. - Measured structural coverage (gcov, host): 96.1% lines overall — PtpClockManager 100.0%, TsnOrchestrator 97.9%, GateControlManager 96.0%, FrerManager 88.5%. Per-module branch data in the test report.
- Total suite: 113 tests, 113 passing (GcmTest 26, PtpTest 27, FrerTest 21,
OrchTest 39). Report:
docs/test_reports/unit_test_report_v1.1.0.md.
examples/zonal_gateway_demo.cpp+-DNORXS_BUILD_EXAMPLES=ONCMake target: runnable end-to-end lifecycle demo (Init → kRunning → fault injection → kDegraded → kSafeState → audit-trail dump) against a simulated switch ASIC..github/workflows/codeql.yml— CodeQL semantic security analysis (push/PR + weekly), per ISO/IEC 18974 §3.1.5.- CI Job 8 — Doxygen API documentation build; blocks on undocumented public API; publishes the HTML as a build artifact.
.clang-formatand.clang-tidy— local profiles mirroring CI..github/CODEOWNERS— dual review (safety + security) on production code; OSPO ownership of compliance artifacts.CODE_OF_CONDUCT.md;feature_requestissue template with standards-impact checklist; issueconfig.ymlrouting security reports away from public issues.
- Project version 1.0.1 → 1.1.0; SBOM regenerated as
sbom/tsn-zonal-backbone-1.1.0.spdx.json(CI version-sync gate updated). - Root-cause fixes for CI findings (cppcheck + Doxygen, from the first
GitHub Actions run):
GateControlManager::verifyBuffer_is now explicitly initialised in the constructor init-list (cppcheckuninitMemberVar).- The gPTP PI servo's proportional and integral terms now use a portable
ArithmeticShiftRight()helper: in C++14, right-shifting a negative signed value is implementation-defined (cppcheckshiftNegativeLHS, MISRA C++:2008 5-8-1 territory). The helper reproduces the arithmetic (floor) shift exactly via well-defined unsigned operations — verified bit-identical by the existing servo unit tests. - Doxyfile:
@project/@standardsregistered as ALIASES (were "unknown command" warnings), obsoleteHTML_COLORSTYLE/COLS_IN_ALPHA_INDEXtags removed (doxygen 1.9.1 runner),WARN_LOGFILEremoved so warnings reach stderr where the CI job captures them, and per-member pedantic warnings (WARN_IF_UNDOCUMENTED,WARN_NO_PARAMDOC) disabled — the remaining warnings are surfaced as advisory by CI Job 8. - Doxygen docs added to the public
Result/Result<void,E>monad, integer aliases,RegAddr/RegData, and theOrchestratorState,ClockRole,SyncState,FrerRecoveryStateenums.
- CI failure semantics hardened against false reds: cppcheck (Job 7) now
blocks only on
(error)-severity diagnostics and uploads the full report as an artifact (warning-severity and false-positive findings are advisory); the Doxygen job (Job 8) blocks on generation failure / missing HTML output while documentation-completeness warnings are reported as advisory; the CodeQL workflow is guarded withif: !github.event.repository.privateso SARIF upload does not fail on private repositories without GitHub Advanced Security (remove the guard after enabling GHAS to scan private forks).
- DEF-001 (Critical):
TsnOrchestrator::PrevalidateAllSchedules()narrowedkMaxGclEntries(256) tou8, truncating the bound to 0 — every non-empty schedule was rejected withkGclEmptyandInit()could never succeed. The comparison is now widened tostd::size_t, matching the correct pattern inGateControlManager.cpp. Covered by regression testOrchTest.Init_ValidConfig_ReturnsOk_StateInitializing. - DEF-002 (Minor):
TsnOrchestrator::GetHealthMetrics()now aggregates per-stream 802.1Qci drop counters as documented (previously always returned 0). Covered byOrchTest.GetHealthMetrics_AggregatesMacsecAndDropCounters.
tests/test_TsnOrchestrator.cpp— 28 new unit tests for the previously untested master coordinator: 8-phase Init fail-fast semantics, Start/Stop lifecycle, kPtpConverging → kRunning transition (BMCA self-election path), ASIL-D degradation FSM (kRunning → kDegraded on MACsec auth failures; kFault latch), circular audit log content (ISO 26262 §7.4.2), runtime schedule update guards, and consolidated health metrics. Total suite: 97 tests, 97 passing.docs/test_reports/unit_test_report_v1.0.1.md— formal unit test report (environment, per-suite results, defect log, open observations) plus the raw execution logunit_test_log_v1.0.1.txt.
docs/compliance/openchain-iso5230.md— open source license compliance program documentation (OpenChain self-certification route).docs/compliance/openchain-iso18974.md— security assurance program documentation: known-vulnerability detection, intake SLAs, standard practices.docs/compliance/nist-csf-mapping.md— NIST CSF 2.0 mapping across all six functions, at both the process layer and the product layer.sbom/tsn-zonal-backbone-1.0.1.spdx.json— SPDX 2.3 Software Bill of Materials (zero third-party runtime dependencies; GoogleTest declared test-scope only).NOTICE— third-party attribution file;LICENSES/LicenseRef-norxs-RI-1.0.txt— REUSE-style license text directory.- CI Job 6 — SBOM validation, version-sync check, compliance artifact presence, and a machine-enforced zero-third-party-includes gate on production code.
- CI Job 7 — cppcheck security static analysis (blocking on errors), complementing
clang-tidy
cert-*/bugprone-*(ISO/IEC 18974 §3.1.5). .github/dependabot.yml— weekly CI toolchain vulnerability/freshness monitoring.- Pull request template extended with an ISO/IEC 5230 / 18974 compliance checklist.
SECURITY.mdextended with the Security Assurance Program section (SBOM link, monitoring, NIST CSF mapping reference).
README.md: corrected the test inventory (the structure listing previously described onlytest_GateControlManager.cppwith an inaccurate case count), added the Verification & Test Evidence and Compliance Programs sections, and refreshed badges.CMakeLists.txt: project version 1.0.0 → 1.0.1; orchestrator tests added to thenorxs-tsn-teststarget.
1.0.0 — 2026-06-02
Production-grade AUTOSAR C++14 IEEE TSN stack for next-generation Software-Defined Vehicle Zonal Architectures. Enforces zero-packet-loss, sub-microsecond latency guarantees for ASIL-D safety-critical payloads with mathematically verified worst-case delay bounds via Network Calculus. Targets NXP i.MX8X SoC paired with SJA1110 / 88Q5050 switch ASICs.
- Fixed-width integer aliases (
u8/u16/u32/u64/i32/i64) conforming to AUTOSAR A3-9-1 - Complete
ErrorCodeenumeration with reserved numeric ranges per domain: Schedule Validation [100–199], HAL [200–299], Clock [300–399], FRER [400–499], Stream Policing [500–599], MACsec [600–699], General [900–999] Result<T,E>exception-free error monad withIsOk(),IsError(),Value(),Error()— Rust-equivalent?operator viaTSN_RETURN_IF_ERRmacro (MISRA C++:2008 Rule 16-0-4)PtpTimestampcorrected to use plainu64 seconds(avoids MISRA C++:2008 Rule 9-6-4 implementation-defined bitfield layout; IEEE 802.1AS §10.6 compliant 48-bit seconds field)GclEntrywithGateStateBitmaskpacked 8-bit gate mask (TC[7:0])ScheduleParamsincludingmaxSafetyFrameSizeBytesfor guard band computationNetworkCalculusResultstruct carrying per-class WCD, deadline met flags, utilisationTrafficEnvelope(σ, ρ) token-bucket arrival curve for Network Calculus inputFrerStreamEntry— IEEE 802.1CB stream descriptor with disjoint path countStreamFilterInstance— IEEE 802.1Qci per-stream filter and policing ruleOrchestratorState,ClockRole,SyncStateenumerations for system-wide FSM- System-wide constants:
kMinGuardBandNs(12 304 ns at 1 Gbps),kSafetyDeadlineNs(500 µs),kPtpSyncTargetNs(1 µs),kHoldoverDriftNsPerSec(1 µs/s TCXO grade)
- Plane 1 — Init & Register Access:
Init(),WriteRegister(),ReadRegister(),ReadModifyWrite()— supports MDIO, SPI, and PCIe management interfaces - Plane 2 — IEEE 802.1Qbv TAS (GCL):
ApplyGclToPort(),ReadOperGcl(),IsGclSwapPending()with full IEEE 802.1Qbv §8.6.9.4 Admin→Oper double-buffer swap semantics documented inline — prevents race conditions during GCL update - Plane 3 — IEEE 802.1Qci Stream Policing:
SetStreamFilter(),ClearStreamFilter(),GetStreamDropCount()— token-bucket CIR/CBS per stream,blockOnLateFrameDDoS containment - Plane 4 — IEEE 802.1CB FRER:
RegisterFrerStream(),DeregisterFrerStream(),GetFrerStats()— replication and recovery sides, latent error event counters - Plane 5 — IEEE 802.1AE MACsec:
ConfigureMacsecChannel(),RotateMacsecKey(),GetMacsecAuthFailures()— dual-SAK hitless key rotation, AES-GCM-128, replay window - Plane 6 — VLAN & Diagnostics:
SetVlanEntry(),SetTcamRule(),GetPortDropCount(),GetLinkStatus(),GetDeviceIdentifier(),GetPortCount() - AUTOSAR constraints: all methods
noexcept, no dynamic allocation, no exceptions, deleted copy/move constructors and assignment operators
- 7-Stage Validation Pipeline executed before any HAL access:
- Stage 1: EntryCount bounds check [1, 256]
- Stage 2: CycleTime bounds [100 µs, 1 s]
- Stage 3: No zero-interval entries
- Stage 4: Σ(intervalNs) == cycleTimeNs (u64 accumulation, no floating-point)
- Stage 5 (new): ASIL-D Guard Band — TC7 window ≥
FrameNs(maxSafetyFrame) + FrameNs(1538B)= 12 304 ns minimum at 1 Gbps (IEEE 802.1Qbv §8.6.8.4) - Stage 6: Safety window — at least one entry with
gateStates == 0x80(TC7 exclusively) - Stage 7 (new): Network Calculus — Latency-Rate server model WCD analysis
- Network Calculus Engine (
RunNetworkCalculus()):- LR server model:
WCD_i = T_i + B_i + Σ_{j>i} B_j - Integer-only arithmetic (ns domain, u64) — MISRA C++:2008 Rule 6-4-1 compliant
- Per-class blocking time computed by
ComputeBlockingTimeNs() - ASIL-D hard gate:
WCD_TC7 ≤ kSafetyDeadlineNs (500 000 ns) - Results stored in
NetworkCalculusResultfor post-validation audit
- LR server model:
ApplySchedule()— validates then commits viahal_.ApplyGclToPort()DisableSchedule()— atomic fallback to all-queues-open pass-throughVerifyHardwareSchedule()— reads back Oper GCL and compares cycle time + all gate statesGetNetworkCalculusResult()— exposes last WCD analysis for diagnostic telemetry
- Integer PI Servo (no floating-point): Kp = 2^(-2) (shift >>2), Ki = 2^(-5) (shift >>5) — anti-windup clamp ±500 000 000 ns·tick; PHC adjustment clamped ±500 000 ppb
- Sync offset computation:
offset = t2 - t1 - meanPathDelay - correctionper IEEE 802.1AS §11.3.2 - State machine:
kFreeRun → kLocking → kLocked ⇄ kHoldover— kLocked when|offset| < kPtpSyncTargetNs (1 µs) - BMCA (Best Master Clock Algorithm — IEEE 802.1AS §10.3.5):
— Priority1/Priority2/ClockQuality dataset comparison; grandmaster election;
—
ForceGrandmasterRole()for bench/HIL configurations (priority1 = 0) - Holdover mode: activated when Sync silence exceeds
syncTimeoutNs; TCXO drift compensation:driftNs = compensationRate × elapsed / 1e9(integer scaled); budget tracked againstholdoverBudgetNs; returnskPtpHoldoverExpiredon expiry InjectSyncMessage()for HIL/unit test Sync simulationGetCurrentTime(),IsSynchronised(),GetHoldoverRemainingNs()
- O(1) Bitmask Duplicate Detection: 32-entry history bitmask per stream
—
bit = seqNum % 32; if (mask & (1<<bit)) → DUPLICATE— constant-time regardless of window position - Individual Recovery Algorithm (IEEE 802.1CB §10.4): sequence extraction, duplicate check, out-of-window detection, history reset
- Per-path Silence Monitoring:
pathHealthMaskper stream updated on every frame receipt; path declared failed afterrecoveryTimeoutNsof silence on that path index - Latent Error Detection (LED) (IEEE 802.1CB §7.4.5):
over a 10 000-frame window, if duplicate rate < 5% → a redundant path is silently broken;
fires
kFrerLatentErrorto TsnOrchestrator →kDegradedstate transition RegisterStream()/DeregisterStream()— compact static array, no fragmentationOnFrameReceived()— returnsResult<bool>(true = forward, false = discard)GetStreamStats(),GetPathHealth()— full diagnostic telemetry
- 8-Phase Hardware Initialisation (in
Init()): HAL init, VLAN table, stream filters (802.1Qci), MACsec channels, pre-validation of all port schedules (Network Calculus fast-fail), GateControlManager placement-new into static storage, gPTP init, FRER registration - 125 µs Scheduling Loop (
Tick()): a)PtpClockManager::Tick()— servo + BMCA b)FrerManager::Tick()— path health + LED c)TickIntegrityCheck()— GCL hardware readback, MACsec auth failure polling (8 ms interval) d)TickDegradationMachine()— fault-mask evaluation, state transitions e)kPtpConverging → kRunning— GCL load + FRER registration on first gPTP lock - ASIL-D Degradation FSM:
—
kRunning → kDegraded: FRER latent error, MACsec auth failures, GCL integrity mismatch —kRunning/kDegraded → kSafeState: PTP holdover expired, Network Calculus deadline exceeded — Safe state:cfg_.safeStateScheduleapplied on all ports (TC7-exclusive GCL) —kAny → kFault: unrecoverable HAL failure; all schedules disabled; requires hw reset - 64-entry Circular Audit Log (ISO 26262 §7.4.2):
AuditEntry[]with monotonic timestamp, from/to states, trigger ErrorCode, affected port/stream UpdatePortSchedule()— runtime GCL update with full 7-stage re-validationGetHealthMetrics()— consolidated: PTP offset, fault mask, total drops, MACsec failures
(count corrected in v1.0.1 — originally misstated as 28; the 1.0.0 release also shipped test_PtpClockManager.cpp (22 cases) and test_FrerManager.cpp (21 cases), omitted from this entry)
MockSwitchHalwith failure injection (failApplyGcl,failReadOperGcl,reportSwapPending)- Full MC/DC coverage on all 7 validation stages
- Guard band boundary conditions: exact minimum, below minimum, above minimum
- Network Calculus result availability before/after
ApplySchedule() - HAL interaction: call count, port ID, failure isolation (validation failure → no HAL call)
- State management:
GetActiveSchedule()before/after,DisableSchedule()effect - Hardware integrity:
VerifyHardwareSchedule()match, HAL read failure, before-apply guard - Successive updates: second schedule overwrites first correctly
norxs-tsn-backbonestatic library target with AUTOSAR flags:-fno-exceptions -fno-rtti -fstack-usagenorxs-tsn-testsGoogleTest binary withgtest_discover_testsNORXS_BUILD_TESTS,NORXS_ENABLE_COVERAGE,NORXS_STRICT_WARNINGSoptions- Post-build stack usage report for ISO 26262 Part 6 §9.4.3 verification
- CMake install rules with namespace
norxs::for downstream consumption
- Cortex-A35 arch flags:
-mcpu=cortex-a35 -mtune=cortex-a35 -march=armv8-a+crc aarch64-poky-linux-gcctoolchain with NXP Yocto sysroot supportNORXS_SYSROOTenv var override for CI environments
- Job 1 Build + GoogleTest (x86_64 host)
- Job 2 Cross-compile aarch64,
objdumparchitecture verification - Job 3 Stack usage analysis, ASIL-D enforcement: no function > 1024 B
- Job 4
clang-tidystatic analysis:bugprone-*,cert-*,cppcoreguidelines-* - Job 5 AUTOSAR compliance pattern scan (13 forbidden patterns) + Doxygen header check