Skip to content
Merged
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
79 changes: 51 additions & 28 deletions docs/RCP-ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,23 @@ Every choice below was derived by comparing the four repos' actual code,
not invented from scratch — each is attributed to the repo(s) whose
existing pattern it's drawn from.

**cpp-RCP v3.0.0 (2026-08-22):** cpp-RCP shipped a full ground-up rewrite,
ported module-by-module from c-RCP's current RC5-conformant
implementation (cpp-RCP issue #129, ROADMAP.md Phase 17 — "first release
where cpp-RCP *is* the OPEN Alliance TC18 Remote Control Protocol").
Several cpp-RCP conformance gaps this document previously tracked as open
(Table 30 Row-2 wiring across all 8 endpoint types, the §13.5.1
compound-wait comparison primitive, and the request.hpp field-level gaps
below) are now closed as a direct result — corrected in place below
rather than left as stale findings. Where a cpp-RCP file is cited below
as the reference shape for some canonical choice, that citation now also
reflects cpp-RCP's substantially larger/more-conformant post-rewrite
content (e.g. its `.fusa-reqs.json` requirement catalog grew from 412 to
1133 entries during the rewrite, and it gained real MC/DC coverage and
TLA+ CI automation it previously lacked entirely) — not re-verified
line-by-line against every canonical choice in this document as part of
this update, only the specific items called out below.

## Module lexicon

One name per protocol concern, used consistently in this document and
Expand Down Expand Up @@ -85,16 +102,14 @@ This table covers all three of Table 30's endpoint-type rows: SPI's own
channel-select row, the GPIO/PWM_OUT write-combining row, and the shared
"Row 2" plain-request rule (`{ADC, PWM_IN, I2C, LIN, CAN, UART, ISELED,
MDIO}`, `evt[2:0]` must be `000b`). A repo can be conformant for the first
two rows while having no implementation at all for Row 2 — that is exactly
cpp-RCP's and rust-RCP's current state, corrected below (previously this
table wrongly marked both "conformant").
two rows while having no implementation at all for Row 2.

| Repo | SPI row | GPIO/PWM_OUT row | Row 2 (8 endpoint types) |
|---|---|---|---|
| c-RCP | conformant (`rcp_ep_spi_channel_valid()`) | conformant (`rcp_ep_gpio_write_semantics_valid()`) | **conformant (reference implementation, fixed this pass) — `rcp_acf_evt_row2_is_plain()`, called consistently from all 8 endpoint files** |
| c-RCP | conformant (`rcp_ep_spi_channel_valid()`) | conformant (`rcp_ep_gpio_write_semantics_valid()`) | conformant (reference implementation) — `rcp_acf_evt_row2_is_plain()`, called consistently from all 8 endpoint files |
| go-RCP | conformant | conformant | conformant (`acf/evt.go`) |
| cpp-RCP | conformant (`spi::channel_of`) | conformant (`endpoint::WriteSemantics`, called into by e.g. `gpio.hpp`'s `apply_gpio_write`) | **not implemented — none of the 8 Row-2 endpoint types (`can.hpp`, `lin.hpp`, `adc.hpp`, `i2c.hpp`, `uart.hpp`, `iseled.hpp`, `mdio.hpp`, plus PWM_IN) have any ACF-header evt decode or dispatch wiring yet; `mock::Server::dispatch()` only routes EP0/GPIO/SPI. Greenfield work, not a dedup refactor.** |
| rust-RCP | conformant (`SpiChannelSelect::from_sub_opcode`) | conformant (`GpioWriteSemantics::from_sub_opcode`) | **not implemented — `evtgroup.rs`'s `classify_evt_sub_opcode` is a stub that always returns `None` by design (its own doc comment says so); none of `can.rs`/`lin.rs`/`adc.rs`/`i2c.rs`/`uart.rs`/`iseled.rs`/`mdio.rs`/`pwm.rs` (PWM_IN) read `evt` at all. Greenfield work, not a dedup refactor.** |
| cpp-RCP | conformant (`spi::channel_of`) | conformant (`endpoint::WriteSemantics`, called into by e.g. `gpio.hpp`'s `apply_gpio_write`) | **conformant (2026-08-22, cpp-RCP v3.0.0's ground-up rewrite from c-RCP)** — all 8 Row-2 endpoint types (`can.hpp`, `lin.hpp`, `adc.hpp`, `i2c.hpp`, `uart.hpp`, `iseled.hpp`, `mdio.hpp`, `pwm.hpp`'s PWM_IN path) now have real ACF-header evt decode and dispatch wiring, verified directly against the current codebase (this table previously said "not implemented" here, correct as of the prior audit but now stale). |
| rust-RCP | conformant (`SpiChannelSelect::from_sub_opcode`) | conformant (`GpioWriteSemantics::from_sub_opcode`) | conformant (`evtgroup.rs`, wired into all 8 endpoint modules) |

**c-RCP finding, resolved.** Table 30's endpoint-type row
`{ADC, PWM_IN, I2C, LIN, CAN, UART, ISELED, MDIO}` allows `evt[2:0] =
Expand Down Expand Up @@ -185,10 +200,10 @@ Current status per repo:
|---|---|
| c-RCP | **conformant (reference implementation, c-RCP#156/#157)** |
| go-RCP | not yet implemented |
| cpp-RCP | not yet implemented |
| cpp-RCP | **conformant (2026-08-22, cpp-RCP v3.0.0's ground-up rewrite from c-RCP)** — `compound_wait_evt_valid()`/`compound_wait_match()` in `acf.hpp`, the same 8-mode primitive shape as c-RCP's reference, with `evt` threaded through `request.hpp`'s compound-wait encode/decode and real per-request dispatch (this table previously said "not yet implemented" here, correct as of the prior audit but now stale). |
| rust-RCP | not yet implemented |

Porting this to the other three repos is the next item of work: each
Porting this to the other two repos is the next item of work: each
needs (a) the generic 8-mode primitive in its own wire/ACF layer, (b)
`evt` threaded through that repo's own compound-wait encode/decode
surface, and (c) real per-request dispatch wiring in whatever module
Expand Down Expand Up @@ -251,26 +266,34 @@ it is not staged in a `.fusa-reqs-pending.json` entry — it needs a direct
fix (new type or width correction) in a future session.

**cpp-RCP and rust-RCP field-level gaps beneath their correct module
shape (found 2026-08-07):** both repos are correctly cited above as the
*reference shape* for module unification — that assessment stands. But a
closer, field-by-field read against TC18 §11.2.2 found both have real
gaps underneath that good architecture, now staged in each repo's
`.fusa-reqs-pending.json` (see the schema-6 pending-reqs mechanism
above):

- **cpp-RCP**: the opcode/routing/state-machine layer
(`RequestTypeOpcode`'s 8 real TC18 opcodes including 0x06
ClearNonSafestate, `mtv=false` repurposing, `expected_start_state`) is
correctly designed — not the same class of defect as go-RCP's
conditional-envelope layer. But three field-level behaviors are
genuinely absent (the real TC18 field names appear only in comments,
never as real fields/variables/consumed values anywhere in `include/`
or `src/`): Compound's `cmp_exec_delay`/`cmp_repetitions`, Triggered's
`trigger_source_ep`/`trigger_signal_nr`/`trigger_threshold`, and
Timed's `presentation_time` (no scheduling/dispatch logic exists
anywhere — a Timed request today has no distinguishing runtime
behavior from a standard one).
- **rust-RCP**: notably more complete than cpp-RCP — `cmp_exec_delay`/
shape (found 2026-08-07; cpp-RCP re-verified 2026-08-22 after its
ground-up v3.0.0 rewrite from c-RCP — the original finding below is now
stale for cpp-RCP, corrected in place):** both repos are correctly cited
above as the *reference shape* for module unification — that assessment
stands.

- **cpp-RCP (resolved, 2026-08-22)**: the specific field-level gaps this
section previously described — Compound's `cmp_exec_delay`/
`cmp_repetitions`, Triggered's `trigger_source_ep`/`trigger_signal_nr`/
`trigger_threshold`, and Timed's `presentation_time` — are no longer
absent; all are real fields with real scheduling/dispatch logic in the
current `request.hpp` (`CompoundStep::exec_delay`/`repeat_count`,
`TriggeredStep::trigger_source_ep`/`trigger_signal_nr`/
`trigger_threshold` plus real occurrence-count matching, and
`TimedRequest::presentation_time` with real TSCF-admission gating),
verified directly against the codebase, not just its comments. A
smaller, different set of real gaps remains, honestly staged in
cpp-RCP's own `.fusa-reqs-pending.json` as of 2026-08-22 —
`REQ-CMP-008`/`REQ-CMP-009` (encode functions take already-decided
values as plain parameters/forwarded payload rather than deriving them
from a richer request-state type), `REQ-TRIG-003` (same class, for
Triggered), `REQ-CHAIN-003`/`REQ-CHAIN-008` (payload forwarding;
`chained_predecessor` typed as `std::optional<uint8_t>` rather than a
richer link type), and `REQ-TIMED-012`/`REQ-TIMED-013` (TSCF-admission
primitives exist but a specific dispatch-wiring path is incomplete) —
narrower shape/wiring items, not the field-presence absence this
section originally found.
- **rust-RCP**: notably more complete than cpp-RCP was — `cmp_exec_delay`/
`cmpw_exec_delay`, `trigger_exec_delay`, and `trigger_repetitions`
(`TriggerRepeatCount`/`is_trigger_repeat_exhausted`) are all real,
well-tested implementations already. Two gaps remain: Compound/
Expand Down
Loading