Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 40 additions & 32 deletions .fusa-reqs.json
Original file line number Diff line number Diff line change
Expand Up @@ -882,128 +882,128 @@
},
{
"id": "REQ-WDG-001",
"title": "Keeper kicks all zones periodically",
"text": "watchdog::Keeper shall send a CmdWatchdog command to every registered zone controller at the configured interval.",
"title": "StreamWatchdog reports overflow per rx_wd_enable/rx_wd_timeout_interval",
"text": "rcp::watchdog::StreamWatchdog::check shall report HealthEvent::overflowed only once more than RequestStreamConfig::rx_wd_timeout_interval milliseconds have elapsed since the stream's last kick_from_request call, and only while RequestStreamConfig::rx_wd_enable is set.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-WDG-002",
"title": "Zone starts Healthy",
"text": "A zone controller shall be in the Healthy state immediately after Keeper construction.",
"title": "kick_from_request resets the watchdog for any inbound request",
"text": "rcp::watchdog::StreamWatchdog::kick_from_request shall reset that stream's watchdog on every call, regardless of the accepted request's kind or is_safety tag.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-WDG-003",
"title": "Degraded after degrade_after misses",
"text": "A zone controller shall transition to Degraded after degrade_after consecutive kick failures.",
"title": "Overflow purges normal requests and retains safety-tagged ones when safestate-enabled",
"text": "rcp::watchdog::StreamWatchdog::check shall, on overflow while RequestStreamConfig::rx_wd_safestate_enable is set, latch the stream into safe state and cancel every pending/started non-safety request on the supplied RequestLedger while leaving is_safety=true records untouched, reporting HealthEvent::entered_safe_state and the purge count; it shall latch nothing and purge nothing when rx_wd_safestate_enable is clear.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-WDG-004",
"title": "Faulted after fault_after misses",
"text": "A zone controller shall transition to Faulted after fault_after consecutive kick failures.",
"title": "Latched safe state does not re-fire until explicitly cleared",
"text": "Once rcp::watchdog::StreamWatchdog::check has latched a stream into safe state, subsequent check calls shall not re-detect overflow for that stream until clear_safe_state is called.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-WDG-005",
"title": "Recovery to Healthy on success",
"text": "A zone controller shall transition back to Healthy on the next successful kick after any degraded or faulted state.",
"title": "Repeating info notification while latched",
"text": "rcp::watchdog::StreamWatchdog::check shall report HealthEvent::info_notification_due on every call while the stream is latched into safe state and RequestStreamConfig::rx_wd_info_enable is set, and shall not report it otherwise.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-WDG-006",
"title": "Callback fires on transition",
"text": "The health callback shall be invoked with the new HealthState whenever a zone's health state changes.",
"title": "Manager multiplexes independent per-stream watchdog state",
"text": "rcp::watchdog::Manager shall track each registered stream_key's watchdog state independently, such that kicking, overflowing, or latching one registered stream shall not affect any other registered stream's state.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-WDG-007",
"title": "Kick timeout respected",
"text": "Each kick shall use a Context with the configured timeout; a timeout response shall count as a miss.",
"title": "Unregistered stream operations report stream_not_registered",
"text": "rcp::watchdog::Manager::on_request_received, poll, and clear_safe_state shall return WatchdogErrc::stream_not_registered, unchanged, for any stream_key not passed to register_stream, without altering any other registered stream's state.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-WDG-008",
"title": "Close stops background thread",
"text": "Keeper::close() shall cause the background kick thread to terminate without hanging.",
"title": "Subscribed callbacks fire in registration order",
"text": "rcp::watchdog::Manager::poll shall invoke every callback registered via subscribe, in registration order, exactly once for each HealthEvent it produces.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-DL-001",
"title": "Monitor subscribes to all zones",
"text": "deadline::Monitor shall subscribe to each registered zone controller's Status stream on construction.",
"title": "Never-reported target is dead",
"text": "rcp::deadline::LivenessTracker::dead shall return true for a target on which note_activity has never been called, regardless of the elapsed time argument.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-DL-002",
"title": "Dead event on initial deadline",
"text": "The monitor shall emit LivenessEvent{alive=false} for any zone that does not publish a Status within the configured deadline, including the very first deadline period.",
"title": "Heartbeat and lifecycle-change signals are independently sufficient",
"text": "rcp::deadline::Monitor::note_heartbeat and note_lifecycle_change shall each independently reset a registered target's last-seen-activity clock, such that either call alone is sufficient to keep that target's LivenessTracker::dead false within the configured deadline.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-DL-003",
"title": "Repeated dead events suppressed",
"text": "The monitor shall not re-emit LivenessEvent{alive=false} for a zone that is already known to be dead.",
"title": "Dead event fires on the first check of a never-reported target",
"text": "rcp::deadline::Monitor::check shall emit LivenessEvent{alive=false} for a registered target that has never received a note_heartbeat/note_lifecycle_change call, on the first check call that evaluates it.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-DL-004",
"title": "Alive event on first status",
"text": "The monitor shall emit LivenessEvent{alive=true} when the first Status arrives for a previously-dead zone.",
"title": "Repeated dead events suppressed",
"text": "rcp::deadline::Monitor::check shall not re-emit LivenessEvent{alive=false} for a target whose alive state was already reported false by a prior check call.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-DL-005",
"title": "Deadline timer resets on status",
"text": "Receipt of a Status shall reset the per-zone deadline timer.",
"title": "Alive event fires on recovery",
"text": "rcp::deadline::Monitor::check shall emit LivenessEvent{alive=true} for a target whose prior reported state was dead once a note_heartbeat/note_lifecycle_change call has occurred within the configured deadline before that check call.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-DL-006",
"title": "alive() returns false before first status",
"text": "Monitor::alive(z) shall return false for any zone that has not yet published a Status.",
"title": "alive() returns false before any check",
"text": "rcp::deadline::Monitor::alive shall return false for any target not yet evaluated by check, including a target that has already received a note_heartbeat/note_lifecycle_change call.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-DL-007",
"title": "Close terminates watch threads",
"text": "Monitor::close() shall signal all watch threads to stop.",
"title": "Subscribed callbacks fire in registration order",
"text": "rcp::deadline::Monitor::check shall invoke every callback registered via subscribe, in registration order, exactly once for each LivenessEvent it produces.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-DL-008",
"title": "Destructor joins threads",
"text": "The Monitor destructor shall join all watch threads before returning.",
"title": "Targets are evaluated independently",
"text": "rcp::deadline::Monitor::check shall evaluate each registered target's liveness independently, such that one target's deadline expiry or recovery shall not affect any other registered target's reported alive state.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
Expand Down Expand Up @@ -2912,6 +2912,14 @@
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-LIFECYCLE-007",
"title": "State-changed callback fires only on an actual state change",
"text": "ServerLifecycle::subscribe_state_changed callbacks shall be invoked with (previous, current) exactly once for every advance() or deconfigure() call that changes state(), in registration order, and shall not be invoked for a call that fails or that leaves state() unchanged.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-REGMAP-001",
"title": "Generic vs. functional endpoint config split",
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.21)

project(cpp-rcp
VERSION 2.9.0
VERSION 2.10.0
DESCRIPTION "Remote Control Protocol for automotive zonal architecture (C++)"
HOMEPAGE_URL "https://github.com/SoundMatt/cpp-RCP"
LANGUAGES CXX
Expand Down
58 changes: 58 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,64 @@ pattern in `rcp/lifecycle.hpp`/`rcp/regmap.hpp`/`rcp/wakeup.hpp`.
- Depends on: RC Server lifecycle & register map (v2.1.0), E2E safe points
(v2.6.0)

**Done (v2.10.0):** `rcp/watchdog.hpp` is replaced in full, per the
Satellite Package Disposition table's entry for this file — the prior
client-driven `CommandType::Watchdog` kick model built on `rcp.hpp`'s
`Zone`/`Command`/`Controller` is discarded, not adapted. The actual
per-stream watchdog timeout/latch primitive already existed as
`rcp::e2e::RxWatchdog` (v2.6.0); this milestone's real work is the driver
layer around it. `watchdog::StreamWatchdog::kick_from_request` resets a
stream's watchdog on every accepted inbound request regardless of kind or
safety tag, matching the "reset by *any* inbound request" rule directly;
`StreamWatchdog::check` reads a live `regmap::RequestStreamConfig` on every
poll, reports `HealthEvent::overflowed` on timeout, and — only when
`rx_wd_safestate_enable` is set — calls `rcp::e2e::apply_watchdog_overflow`
to latch safe state and purge normal (non-safety) requests from the
supplied `request::RequestLedger`, exactly the v2.6.0 purge-normal/
retain-safety rule reused unmodified. `watchdog::Manager` multiplexes
`StreamWatchdog` across every request stream the embedding application
registers, keyed by an opaque `uint64_t` (typically an
`avtp::StreamId::to_u64()`), and fans out `HealthEvent`s to subscribed
callbacks — this is the "driver/wiring layer" the roadmap called for, not
a reimplementation of watchdog detection itself.

`rcp/deadline.hpp` is likewise rebuilt in full per the disposition table's
"ADAPT" call for this file: the concept of "declare a target dead once its
liveness signal goes silent past a deadline, alive again once it resumes"
survives from the pre-replacement `Monitor`, but every concrete signal
source is rebound away from `Status`-subscription polling, which does not
exist in the target model. Two independent liveness signals feed the new
`deadline::Monitor`, matching the roadmap's own "and/or": `note_heartbeat`
for `regmap::ResponseQueueConfig::flush_time`'s periodic flush cadence, and
`note_lifecycle_change` for `lifecycle::ServerLifecycle`'s new
`subscribe_state_changed` trigger — either alone is sufficient evidence of
liveness. Both `ResponseQueueConfig::flush_time` and
`ServerLifecycle::subscribe_state_changed` are small, explicitly-scoped
additions landed at this milestone (see those headers' own v2.10.0 comments)
since neither existed in the tree before this rebuild needed them; both are
purely additive; every pre-existing field and transition rule in
`regmap.hpp`/`lifecycle.hpp` is unchanged. `deadline::Monitor::check`
evaluates every registered target independently, emitting a
`LivenessEvent` on each alive/dead transition (including the initial dead
report for a target that has never reported) and suppressing repeats,
carrying forward the pre-replacement `Monitor`'s alive/dead semantics
without its background-thread-per-zone machinery — this header, like every
other one touched since v2.6.0, provides primitives driven by the
embedding application's own clock/scheduler, not a running thread of its
own.

Nothing else in this tree depended on the old `watchdog::Keeper` or
`deadline::Monitor` APIs (only their own tests did; `rcp/redundancy.hpp`
mentions `watchdog::Keeper` only in a doc comment, with no code dependency
on it), so no legacy shim was needed, same as every other Phase 14 rebuild.
New/rewritten coverage lives in `tests/test_watchdog.cpp`
(`REQ-WDG-001..008`, entirely rewritten), `tests/test_deadline.cpp`
(`REQ-DL-001..008`, entirely rewritten), and `tests/test_lifecycle.cpp`
(`REQ-LIFECYCLE-007`, new), traced in `.fusa-reqs.json`. Full bit-for-bit
conformance against other TC18 implementations is not claimed — see this
file's own disclaimer pattern in `rcp/e2e.hpp`/`rcp/regmap.hpp`/
`rcp/lifecycle.hpp`/`rcp/powerstate.hpp`.

### 55. Authorization & Admission-Control Rebind (v2.11.0)

- Rebind `authz.hpp`'s access-policy check from
Expand Down
Loading
Loading