Skip to content

feat: implement Table 30 Row-2 evt[2:0] validation — MDIO (8th and last endpoint type) - #162

Merged
SoundMatt merged 2 commits into
mainfrom
feat/table30-row2-evt-mdio
Aug 20, 2026
Merged

feat: implement Table 30 Row-2 evt[2:0] validation — MDIO (8th and last endpoint type)#162
SoundMatt merged 2 commits into
mainfrom
feat/table30-row2-evt-mdio

Conversation

@SoundMatt

Copy link
Copy Markdown
Owner

Summary

TC18 §13.5 Table 33 ("EP specific usage of evt-field", TC18.txt L4076-4116) groups 8 RCP endpoint types — {ADC, PWM_IN, I2C, LIN, CAN, UART, ISELED, MDIO} — into a shared "Row 2" evt[2:0] request-side rule. mdio.rs becomes the eighth and last of these to call the shared evtgroup::evt_row2_kind_of predicate, closing out the full Table 30/33 Row-2 evt[2:0] validation rollout across this crate (8/8 endpoint types), following the pattern established in #155 (I2C pilot), #156 (ADC), #157 (PWM_IN), #158 (LIN), #159 (CAN), #160 (UART), and #161 (ISELED).

New pub items (MINOR bump, v5.10.0v5.11.0 per docs/SEMVER.md):

  • mdio::MdioRequest / mdio::MdioRequest::from_evt_sub_opcode

Signature shape

MdioRequest::from_evt_sub_opcode takes an already-decoded MdioTransfer, not raw byte_msg_payload bytes — mirroring can::CanRequest's/iseled::IseledRequest's own shape rather than i2c::I2cRequest's/lin::LinRequest's/adc::AdcRequest's/pwm::PwmInRequest's/uart::UartRequest's raw-bytes shape. MdioTransfer already has its own dedicated decode entry point (MdioTransfer::decode, pre-existing this item and unchanged by it), so this evt[2:0]-classification entry point does not re-derive that byte-layout logic a second time internally.

The ConfigWrite judgment call (this PR's independent decision)

Two precedents exist in this crate:

  • I2C/LIN/ADC/PWM_IN/UART: evt[2:0] == 111bOk(Self::ConfigWrite)
  • CAN/ISELED: evt[2:0] == 111bErr(RcpError::ConfigWriteNotImplemented) — because their from_evt_sub_opcode requires an already-decoded frame value (CanDataFrame/IseledFrame), and a genuine TC18 §12.7.1 config-write payload cannot be honestly decoded into one: CanDataFrame::decode/IseledFrame::decode each make a real structural claim about their bytes (parsed FrameFormat/id/data or chain_address/command/data), and can fail or silently misinterpret unrelated bytes as if they were a real frame.

MDIO's from_evt_sub_opcode shares CAN/ISELED's signature shape (already-decoded frame parameter), but I chose to keep the Ok(Self::ConfigWrite) precedent, not follow CAN/ISELED's departure. Reasoning:

MdioTransfer::decode is infallible and interprets no structure at all — this module's own pre-existing doc comment already establishes this ("Provenance note: register-access framing is carried opaque"): every byte slice, including an empty one, is a valid MdioTransfer, and the type asserts nothing about what its bytes mean beyond "these are the bytes of this request" — explicitly matching i2c::I2cByteTransfer's own raw pass-through discipline. A caller can therefore decode a genuine TC18 §12.7.1 config-write payload through MdioTransfer::decode with zero information loss and zero misrepresentation, unlike a CanDataFrame or IseledFrame. The "no caller can honestly construct one" pressure that drove CAN's/ISELED's departure simply does not apply to MDIO's own always-valid, opaque-bytes shape. So MdioRequest::from_evt_sub_opcode follows the majority precedent: Ok(Self::ConfigWrite), discarding the supplied MdioTransfer for that arm exactly as I2C discards its raw payload bytes.

This is a deliberate, independently-reasoned "third path" — CAN/ISELED's signature, I2C's ConfigWrite semantics — not a mechanical copy of either whole precedent. Full reasoning is in mdio.rs's own new "Provenance note: evt[2:0] request validation" doc comment section.

Every Reserved sub_opcode value (evt[2:0] in 001b..=110b, or any value outside the 3-bit field) is rejected with Err(RcpError::UnsupportedCmd), unchanged from every prior Row-2 endpoint-type module.

Confirming the existing MDIO encoding was NOT touched

mdio.rs's own doc comments document a "Divergence note: mdio_mode does not select Clause 22 vs Clause 45" — a previously-invented, non-spec-derived Clause-22/45-style addressing scheme with no real TC18 basis (the same issue class this crate's own ISELED module documented for issue #71, and MDIO's own cpp-RCP counterpart documented for issue #72). This PR does not touch, "improve", or reinterpret MdioAddressingMode, MdioFunctionalConfig, or any existing MdioTransfer/MdioTransferResult encoding. It is scoped strictly to evt[2:0] request classification — a completely separate concern.

Pre-existing citation drift found (flagged, not fixed — separate follow-up)

While independently re-verifying the new TC18.txt citations this item adds, I spot-checked mdio.rs's existing citations against /Users/matt/Coding/SoundMatt/TC18.txt and found the same class of drift this crate's own ISELED PR (#161) found and flagged (~400 lines, from a stale reference-file version):

mdio.rs cites Actual location in TC18.txt
"Table 57" / TC18.txt line 5676 (MDIO's own mdio_mode field table) Table 60 ("Usage of ABB message for mdio requests") / line 6088
"Figure 42" / TC18.txt line 5664 (MDIO's own request format) Figure 43 ("mdio request format") / line 6077
"Table 56" / TC18.txt line 5639 (MDIO functional-config register layout) Table 59 ("MDIO functional configuration") / line 6061

Both the line numbers and the table/figure numbers have drifted (line 5676 in the current TC18.txt actually falls inside an unrelated ADC/PWM example figure, not MDIO's section at all). I did not correct these pre-existing citations — that is out of scope for this evt[2:0]-classification item, per task instructions — but flagged the drift explicitly in mdio.rs's own new "Editorial note: pre-existing §13.7.13 citation drift" section and in CHANGELOG.md, so it can be tracked as a separate, deliberate follow-up (matching how #161 flagged ISELED's own drift).

The two new citations this PR adds (§13.5 Table 33 Row-2, TC18.txt L4085-4092; §13.7.13.3 "MDIO request handling", TC18.txt L6065-6066; Figure 43, TC18.txt L6077) were independently re-verified against TC18.txt rather than copied from this module's own now-known-stale citations.

Verification

  • cargo build / cargo test: clean, all tests pass (17 new/existing mdio::tests::* including Reserved-range rejection 0b001..=0b110, out-of-3-bit-field rejection, and a never-panics sweep over the full u8 range × 3 sample transfers).
  • Mutation test: temporarily changed the Reserved arm to return Ok(Self::Plain(MdioTransfer::default())) instead of Err(RcpError::UnsupportedCmd)mdio_request_reserved_evt_values_are_rejected_with_unsupported_cmd and mdio_request_values_above_the_3_bit_field_are_also_rejected_with_unsupported_cmd both failed as expected. Reverted cleanly; cargo test passes again and git diff shows no leftover.
  • bash scripts/api-snapshot-check.sh: OK — public API surface matches docs/PUBLIC_API.txt (regenerated for real via cargo +nightly public-api --simplified, not hand-patched).
  • rsfusa check --dir .: 0 errors (794 pre-existing warnings/65 infos, unrelated to this change).
  • rsfusa trace --dir .: Total: 628 Traced: 628 Tested: 628 — 100% traced and tested crate-wide, including the two new REQ-MDIO-007/REQ-MDIO-008 entries.

Not in this PR

Wiring MdioRequest::from_evt_sub_opcode into mock::RcServer's actual dispatch — mock::Endpoint's trait signature still does not carry an evt value to any implementation at all, the same gap every prior Row-2 endpoint-type module's own item found and left as-is.

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com

SoundMatt and others added 2 commits August 20, 2026 09:03
…st endpoint type)

TC18 §13.5 Table 33 groups 8 RCP endpoint types (ADC, PWM_IN, I2C, LIN,
CAN, UART, ISELED, MDIO) into a shared Row-2 evt[2:0] request-side rule.
mdio.rs becomes the eighth and last of these to call the shared
evtgroup::evt_row2_kind_of predicate, closing out the full Table 30/33
Row-2 evt[2:0] validation rollout (8/8 endpoint types).

New pub items (MINOR bump, v5.10.0 -> v5.11.0):
- mdio::MdioRequest / mdio::MdioRequest::from_evt_sub_opcode

Signature shape: from_evt_sub_opcode takes an already-decoded
MdioTransfer (mirroring can::CanRequest/iseled::IseledRequest), not raw
byte_msg_payload bytes (unlike i2c/lin/adc/pwm/uart), because
MdioTransfer already has its own dedicated decode() entry point.

ConfigWrite judgment call: kept the Ok(Self::ConfigWrite) majority
precedent (i2c/lin/adc/pwm/uart) rather than following can.rs's/
iseled.rs's Err(RcpError::ConfigWriteNotImplemented) departure. That
departure rests on CanDataFrame/IseledFrame making a real structural
claim about their bytes that a genuine TC18 §12.7.1 config-write payload
cannot honestly satisfy (decode can fail or silently misinterpret
unrelated bytes). MdioTransfer::decode is infallible and interprets no
structure at all -- every byte slice is a valid MdioTransfer, matching
i2c::I2cByteTransfer's own raw pass-through discipline -- so a caller can
honestly construct one from a genuine config-write payload with zero
misrepresentation. The 'no caller can honestly construct one' pressure
that drove CAN's/ISELED's departure does not apply to MDIO.

Did not touch: MdioAddressingMode, MdioFunctionalConfig, or any existing
MdioTransfer/MdioTransferResult encoding -- this module's own pre-existing
'Divergence note' documents a previously-invented, non-spec-derived
Clause 22/45 addressing scheme (the same issue class as ISELED's #71 and
cpp-RCP's MDIO #72). This PR is scoped strictly to evt[2:0] classification
and does not reinterpret that encoding.

Citation drift found (not fixed here, flagged as follow-up): mdio.rs's
pre-existing citations for MDIO's own request-format/mdio_mode table cite
'Table 57'/TC18.txt L5676 and 'Figure 42'/TC18.txt L5664; against current
TC18.txt these are actually Table 60/L6088 and Figure 43/L6077. Its
functional-config citation ('Table 56'/L5639) is actually Table 59/L6061.
Same ~400-line/3-number drift class iseled.rs's own v5.10.0 item found.
Not corrected here per task scope -- flagged in mdio.rs's own new
'Editorial note: pre-existing §13.7.13 citation drift' section and in
CHANGELOG.md. New citations added by this item were independently
re-verified against TC18.txt.

Also: .fusa-reqs.json REQ-MDIO-007/008, ARCHITECTURE.md Table 30
centralization row update, docs/PUBLIC_API.txt regenerated via
cargo +nightly public-api, tests mirroring CAN/ISELED's shape (Reserved
001b-110b rejection, out-of-3-bit-field, never-panics).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: SoundMatt <47545907+SoundMatt@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Matt <47545907+SoundMatt@users.noreply.github.com>
@SoundMatt
SoundMatt merged commit 785df11 into main Aug 20, 2026
18 checks passed
@SoundMatt
SoundMatt deleted the feat/table30-row2-evt-mdio branch August 20, 2026 16:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant