From 21d13d98fcd45482a2cad37b4a29826b4f08d572 Mon Sep 17 00:00:00 2001 From: Matt <47545907+SoundMatt@users.noreply.github.com> Date: Sat, 22 Aug 2026 09:42:24 -0700 Subject: [PATCH] =?UTF-8?q?rewrite(phase6):=20batch=209=20=E2=80=94=20MDIO?= =?UTF-8?q?/PWM=20catalog=20re-derivation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of the v3.0.0 ground-up rewrite (cpp-RCP #129, ROADMAP.md Phase 17), branch rewrite/v3-from-c-rcp. Phase 6 (requirement catalog), batch 9 of 13. ## Scope mdio.hpp's REQ-MDIO-* (c-RCP: 28 entries), pwm.hpp's REQ-PWM-* (75, the largest single per-endpoint prefix in the whole catalog) -- 103 c-RCP entries total. ## Major finding: same pattern as batches 7/8 Both modules' code and tests were already ported ahead of the catalog in an earlier untracked pass -- mdio.hpp/test_mdio.cpp needed zero edits at all (top-of-file manifests already covered the full 28-id c-RCP range). The gap was almost entirely catalog-side, plus 14 pre-existing low-numbered id collisions. ## New catalog entries (87) - MDIO: 21 (REQ-MDIO-008-028) - PWM: 66 (REQ-PWM-010-026, 060-075 minus already-covered/collision ids) ## Id-collision gaps filed (14) - MDIO: 7 (001-007) -- old entries describe unrelated pre-rewrite content (ep_type id, payload width validation); real c-RCP content (addr_valid, burst_next_regad, word_encode/decode, pack_len/words, word_count_of) genuinely implemented+tested under the same bracket numerals -- a legitimate dual-tag overlap, not a gap. - PWM: 7 (001, 004-009) -- verified content collisions directly, e.g. cpp's REQ-PWM-008 carries severity:cybersecurity and describes handle_request Row-2 classification, while c-RCP's real REQ-PWM-008 (RESERVED4 no-op) is unrelated and genuinely tested elsewhere. REQ-PWM-001 is an honest architecture divergence, not force-fit as a collision or a gap: cpp has no validate-and-reject write_semantics_valid(); endpoint::write_semantics_of() masks to 3 bits instead, making every input constructively valid -- same safety property, different shape, cited to test_endpoint.cpp's REQ-ENDPOINT-002 tests. ## Already-covered, no action (2) REQ-PWM-002 (exact 1:1 match), REQ-PWM-003 (cpp's own entry bundles Or/And/Xor/Add/Subtract under one id; OR is a literal subset). ## Real tested-coverage gaps found and closed (2, following batch 8's lesson) Grepped the whole include/+tests/ tree for every id before adding it (per the explicit instruction added to this batch's dispatch after batch 8's CI-caught miss): found REQ-PWM-041 (PWM_IN strerror uniqueness -- cpp shares one PwmErrc/pwm_category() across PWM_OUT/ PWM_IN, unlike c-RCP's two separate functions, so no dedicated test existed) and REQ-PWM-061 (decode_read_request rejects a non-ACF_ABB frame -- no test covered bad_msg_type for PWM_OUT's read-request decode at all). Strengthened the existing REQ-PWM-024 message test into an exhaustive non-empty/distinct-message-per-code loop (dual- tagged [REQ-PWM-024][REQ-PWM-041]), and added a new TEST_CASE for REQ-PWM-061 mirroring test_mdio.cpp's existing pattern for the same check. ## Verification Independently re-verified (the porting agent's own final step re-ran a whole-catalog tag-coverage script covering all 869 entries, not just this batch's 103 -- confirming no regression to batches 1-8): semantic id-keyed diff confirms zero pre-existing entries modified/ deleted, exactly 87 new ids matching the report's per-prefix breakdown exactly (MDIO 21, PWM 66), zero duplicate ids. Independently re-ran my own from-scratch Python tag-coverage check against the merged worktree (not trusting the agent's script output alone): confirmed 869/869 entries have both a real //fusa:req and a real //fusa:test-or-bracket tag somewhere in the tree, zero gaps. Confirmed no new entry carries severity:cybersecurity -- sec-tested count holds exactly at 72/869. Full tree rebuilt from scratch: 0 errors, 0 warnings, 58/58 ctest suites pass (100%). .fusa-reqs.json: 782 -> 869 entries (+87, 8003 -> 9026 lines). .fusa-reqs-pending.json: 73 -> 87 entries (+14, 783 -> 961 lines). tests/test_pwm.cpp: +42 lines. include/rcp/mdio.hpp, include/rcp/pwm.hpp, tests/test_mdio.cpp: unchanged. Co-Authored-By: Claude Sonnet 5 Signed-off-by: Matt <47545907+SoundMatt@users.noreply.github.com> --- .fusa-reqs-pending.json | 178 +++++++ .fusa-reqs.json | 1023 +++++++++++++++++++++++++++++++++++++++ tests/test_pwm.cpp | 42 ++ 3 files changed, 1243 insertions(+) diff --git a/.fusa-reqs-pending.json b/.fusa-reqs-pending.json index 80e7463..e88acd0 100644 --- a/.fusa-reqs-pending.json +++ b/.fusa-reqs-pending.json @@ -778,6 +778,184 @@ "level": "ASIL-B", "asil": "ASIL-B", "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 8, ADC (adc.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/adc.hpp / tests/test_adc.cpp. The blocker is that cpp-RCP's pre-existing REQ-ADC-* catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Unlike some of this batch's other id-collisions (I2C/GPIO), this one is a clean single-occupant mismatch, not a dual-tag overlap: cpp's ADC module was fully redesigned from its pre-rewrite AdcEndpoint::request_reading()/compute_average()/handle_request() shape (which this catalog's own existing entry at this id describes) to a new average_interval()/collect_response_values()/response_value_count()/execute_measurement_cycle() pipeline matching c-RCP's real design -- the old functions this catalog entry names no longer exist in include/rcp/adc.hpp at all (grep-verified: compute_average, AdcEndpoint::request_reading, AdcEndpoint::request_reading_from_trigger_queue, AdcEndpoint::handle_request, and encode_adc_value are all absent), so no tag anywhere in the file still points to this catalog entry's own described behavior. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision, retire the stale old entry, and migrate this entry in. Already taken by: this catalog's own REQ-ADC-009 (\"AdcEndpoint::handle_request reports config-write (evt[2:0]==111b) as not yet supported\"). Genuinely implemented+tested: rcp::adc::collect_response_values(avg, n, out) (include/rcp/adc.hpp) copies an avg[i].value equal to kAdcNoSignal into out_values unchanged, never substituting or averaging it away -- tests/test_adc.cpp's \"collect_response_values packs averaged values in capture order, verbatim\" TEST_CASE (tagged REQ-ADC-006 and REQ-ADC-009 together) proves the middle kAdcNoSignal entry of {10, kAdcNoSignal, 30} survives unchanged in the output." + }, + { + "id": "REQ-MDIO-001", + "title": "rcp_ep_mdio_addr_valid() validates a Clause-22/Clause-45 MDIO address", + "text": "rcp_ep_mdio_addr_valid() shall return false for any prtad above RCP_EP_MDIO_PRTAD_MAX, for a RCP_EP_MDIO_CLAUSE_22 address with a nonzero devad or a regad above RCP_EP_MDIO_CLAUSE22_REGAD_MAX, for a RCP_EP_MDIO_CLAUSE_45 address with devad above RCP_EP_MDIO_DEVAD_MAX, and for any other clause value; true otherwise. CORRECTED (2026-08-10, c-RCP-AUDIT-06, issue #256 Group D): the field widths this function validates (5-bit prtad/devad/Clause-22-regad) are independently public knowledge of IEEE 802.3 Clause 22/45, per ep_mdio.h's own file header (\"Two addressing modes: Clause-22 MMD and Clause-45 MMS\") -- not values TC18 §13.7.13 itself defines (TC18's own mdio_address field is only described as \"As per IEEE & OA SPI spec\", §13.7.13.3 Table 60, with no field-width breakdown of its own). The previous citation (\"An RC Server implementation with an integrated PHY may allow access...\") described an unrelated sentence about integrated-PHY access, not address-field validation; corrected to cite the actual TC18 basis for this endpoint's existence and its own honest field-width disclosure.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.1, TC18.txt L6033-6037 (MDIO EP's own existence and topic area); §13.7.13.3 Table 60 (mdio_address: \"As per IEEE & OA SPI spec\"), TC18.txt L6085 -- TC18 defers this field's own width to an external IEEE/OA reference this codebase does not reproduce, per ep_mdio.h's own file header", + "tc18_master_id": "TC18-13.7.13.3-002", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/mdio.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/mdio.hpp / tests/test_mdio.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-MDIO-001 (\"MDIO's ep_type id is 0x0D\"). Genuinely implemented+tested: rcp::mdio::addr_valid(MdioAddr) (include/rcp/mdio.hpp) is a real constexpr function bounding prtad, and either devad==0/regad<=kClause22RegadMax (Clause22) or devad<=kDevadMax (Clause45), false for any other clause -- tests/test_mdio.cpp's \"addr_valid accepts Clause-22 addresses in range\"/\"addr_valid rejects a Clause-22 address with a nonzero devad\"/\"addr_valid rejects a Clause-22 regad above 5 bits\"/\"addr_valid accepts Clause-45 addresses in range\"/\"addr_valid rejects a Clause-45 devad above 5 bits\"/\"addr_valid rejects prtad above 5 bits for either clause\"/\"addr_valid rejects an unknown clause value\" TEST_CASEs (all tagged [REQ-MDIO-001], sharing this numeral with the catalogued \"MDIO's ep_type id is 0x0D\" test) exercise every boundary this function defines." + }, + { + "id": "REQ-MDIO-002", + "title": "rcp_ep_mdio_burst_next_regad() computes the next burst register address", + "text": "rcp_ep_mdio_burst_next_regad() shall return regad+1 wrapped modulo 32 for RCP_EP_MDIO_CLAUSE_22, regad+1 wrapped modulo 65536 for RCP_EP_MDIO_CLAUSE_45, and regad unchanged for any other clause value. NOTE (2026-08-10, c-RCP-AUDIT-06, issue #256 Group D): this wraparound rule -- and the whole burst/post-increment-addressing concept it implements -- is this module's own original engineering design (ep_mdio.h's own file header, \"Single-word and burst addressing\": \"this module's own generalization of the well-known MDIO post-increment addressing idiom... not a spec-mandated behavior\"), not derived from TC18 §13.7.13's own text, which describes no burst/word_count concept at all -- Table 60's mdio_mode field instead selects access width via 4 discrete values. Corrected from carrying no citation at all (implying an undisclosed TC18 conformance basis) to an honestly-cited entry, matching ep_iseled.h's own precedent of keeping ASIL-B for a module's original engineering design that is nonetheless directly relied upon by this endpoint type's own safety-relevant address-space bounds.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.1, TC18.txt L6033-6037 (cited only as attribution for which general topic area -- MDIO management access -- motivated this endpoint type's existence, per ep_mdio.h's own file header; not as a source for this specific burst-addressing design)", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/mdio.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/mdio.hpp / tests/test_mdio.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-MDIO-002 (\"MDIO mdio_payload width validation per mdio_mode\"). Genuinely implemented+tested: rcp::mdio::burst_next_regad(MdioClause, uint16_t) (include/rcp/mdio.hpp) increments and wraps at kClause22RegadMax for Clause22, wraps at 16 bits for Clause45, and leaves regad unchanged for any other clause value -- tests/test_mdio.cpp's \"burst_next_regad increments within Clause-22's 5-bit range\"/\"burst_next_regad wraps at Clause-22's 5-bit boundary\"/\"burst_next_regad increments within Clause-45's 16-bit range\"/\"burst_next_regad wraps at Clause-45's 16-bit boundary\"/\"burst_next_regad leaves regad unchanged for an unknown clause\" TEST_CASEs (all tagged [REQ-MDIO-002]) exercise every case." + }, + { + "id": "REQ-MDIO-003", + "title": "rcp_ep_mdio_word_encode() encodes a 16-bit register word as two big-endian octets", + "text": "rcp_ep_mdio_word_encode() shall write word's high byte to out[0] and word's low byte to out[1]. NOTE (2026-08-10, c-RCP-AUDIT-06, issue #256 Group D): the big-endian byte order this encodes is this module's own original engineering choice (ep_mdio.h's own file header, \"Wire layout\"), consistent with -- but not itself specified by -- TC18 §13.7.13.3's mdio_payload field, whose own internal byte order TC18 does not spell out. Corrected from carrying no citation at all to an honestly-cited entry.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Table 60 (mdio_payload field), TC18.txt L6086 -- this module's own byte-order choice for that field, not itself specified by the cited text", + "tc18_master_id": "TC18-13.7.13.3-002", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/mdio.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/mdio.hpp / tests/test_mdio.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-MDIO-003 (\"MDIO register write-then-read round-trip\"). Genuinely implemented+tested: rcp::mdio::word_encode()/word_decode() (include/rcp/mdio.hpp) write/read a 16-bit word as two big-endian octets -- tests/test_mdio.cpp's \"word_encode/word_decode round-trip and are big-endian\" TEST_CASE (tagged [REQ-MDIO-003][REQ-MDIO-004], an established dual-tag pattern) exercises the round-trip and the explicit byte order." + }, + { + "id": "REQ-MDIO-004", + "title": "rcp_ep_mdio_word_decode() decodes two big-endian octets as a 16-bit register word", + "text": "rcp_ep_mdio_word_decode() shall return (in[0] << 8) | in[1]. NOTE (2026-08-10, c-RCP-AUDIT-06, issue #256 Group D): the inverse of REQ-MDIO-003's own byte-order choice -- see that entry's own note.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Table 60 (mdio_payload field), TC18.txt L6086 -- this module's own byte-order choice for that field, not itself specified by the cited text", + "tc18_master_id": "TC18-13.7.13.3-002", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/mdio.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/mdio.hpp / tests/test_mdio.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-MDIO-004 (\"MDIO mdio_mode keeps each mode's register space distinct\"). Genuinely implemented+tested: rcp::mdio::word_decode() (include/rcp/mdio.hpp) is the exact inverse of word_encode() -- the same \"word_encode/word_decode round-trip and are big-endian\" TEST_CASE (tagged [REQ-MDIO-003][REQ-MDIO-004]) exercises it." + }, + { + "id": "REQ-MDIO-005", + "title": "rcp_ep_mdio_pack_len() computes the packed byte length of a word count", + "text": "rcp_ep_mdio_pack_len() shall return word_count * 2. NOTE (2026-08-10, c-RCP-AUDIT-06, issue #256 Group D): pure arithmetic over this module's own word_count/burst concept -- see REQ-MDIO-002's own note on that concept's non-TC18-derived origin. Corrected from carrying no citation at all to an honestly-cited entry.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.1, TC18.txt L6033-6037 (cited only as attribution for which general topic area motivated this endpoint type's existence; see REQ-MDIO-002)", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/mdio.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/mdio.hpp / tests/test_mdio.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-MDIO-005 (\"MdioErrc is a distinct error category with a non-empty message\"). Genuinely implemented+tested: rcp::mdio::pack_len(size_t) (include/rcp/mdio.hpp) is a real constexpr function returning word_count*2 -- tests/test_mdio.cpp's \"pack_len is word_count * 2\" TEST_CASE (tagged [REQ-MDIO-005]) exercises it directly." + }, + { + "id": "REQ-MDIO-006", + "title": "rcp_ep_mdio_pack_words() packs a register-word array into a big-endian byte buffer", + "text": "rcp_ep_mdio_pack_words() shall return a zeroed rcp_bytes_t when word_count is 0 or on allocation failure, and otherwise a newly allocated buffer of rcp_ep_mdio_pack_len(word_count) octets holding each word's rcp_ep_mdio_word_encode() result in order.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.1, TC18.txt L6033-6037 (cited only as attribution for which general topic area -- MDIO management access -- motivated this endpoint type's existence, per ep_mdio.h's own file header; not as a source for this specific buffer-packing design; see REQ-MDIO-002/005/007/008)", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/mdio.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/mdio.hpp / tests/test_mdio.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-MDIO-006 (\"MdioEndpoint::handle_request applies Table 33 Row 2 evt[2:0] classification before transacting\"). Genuinely implemented+tested: rcp::mdio::pack_words() (include/rcp/mdio.hpp) packs a word array into a big-endian byte vector, returning an empty vector for word_count 0 -- tests/test_mdio.cpp's \"pack_words/word_count_of/unpack_word_at round-trip\" and \"pack_words returns an empty vector for word_count 0\" TEST_CASEs (both tagged [REQ-MDIO-006]) exercise it." + }, + { + "id": "REQ-MDIO-007", + "title": "rcp_ep_mdio_word_count_of() derives a word count from a packed byte length", + "text": "rcp_ep_mdio_word_count_of() shall return false and leave *out_word_count untouched when byte_len is odd, and otherwise return true with *out_word_count set to byte_len / 2. NOTE (2026-08-10, c-RCP-AUDIT-06, issue #256 Group D): the inverse of REQ-MDIO-005's own word-count/byte-length relationship -- see that entry's own note. Corrected from carrying no citation at all to an honestly-cited entry.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.1, TC18.txt L6033-6037 (cited only as attribution for which general topic area motivated this endpoint type's existence; see REQ-MDIO-002/005)", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/mdio.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/mdio.hpp / tests/test_mdio.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-MDIO-007 (\"MdioEndpoint::handle_request reports config-write (evt[2:0]==111b) as not yet supported\"). Genuinely implemented+tested: rcp::mdio::word_count_of(size_t, size_t&) (include/rcp/mdio.hpp) returns false and leaves out_word_count untouched for an odd byte_len, true with byte_len/2 otherwise -- tests/test_mdio.cpp's \"word_count_of rejects an odd byte length\"/\"word_count_of accepts an even byte length\" TEST_CASEs (both tagged [REQ-MDIO-007]) exercise both branches." + }, + { + "id": "REQ-PWM-001", + "title": "rcp_ep_pwm_out_write_semantics_valid() accepts exactly 0..7", + "text": "rcp_ep_pwm_out_write_semantics_valid() shall return true for every value v with v <= 7, and false for every v > 7.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33 (\"evt[2:0]\" GPIO/PWM_OUT row, values 000b-111b), TC18.txt L4093-4115", + "tc18_master_id": "TC18-13.5-001", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/pwm.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/pwm.hpp / tests/test_pwm.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-PWM-001 (\"PWM_OUT/PWM_IN shared period/active-duration payload shape\"). Genuinely implemented+tested: rcp::endpoint::write_semantics_of(uint8_t) (include/rcp/endpoint.hpp), consumed by rcp::pwm::decode_write_request() (include/rcp/pwm.hpp), masks its argument to the low 3 bits before converting to WriteSemantics, so every possible uint8_t input constructively yields one of the 8 defined WriteSemantics values -- a stricter, always-valid-by-construction architecture than c-RCP's validate-and-reject rcp_ep_pwm_out_write_semantics_valid(), but one that satisfies the same underlying safety property (only a value in 0..7 is ever reachable). tests/test_endpoint.cpp's \"write_semantics_of decodes all 8 evt[2:0] values\"/\"write_semantics_of masks its input down to 3 bits\" TEST_CASEs (tagged [REQ-ENDPOINT-002], a shared, endpoint-agnostic mechanism also relied on by rcp/gpio.hpp) exercise this directly. Architecture divergence, not a missing behavior -- filed here rather than silently dropped, since c-RCP's own id and text describe a validate-then-reject predicate this port does not literally have a same-shaped function for." + }, + { + "id": "REQ-PWM-004", + "title": "rcp_ep_pwm_out_apply_write() implements RCP_EP_PWM_OUT_WRITE_AND per field", + "text": "rcp_ep_pwm_out_apply_write() shall, for evt == RCP_EP_PWM_OUT_WRITE_AND, bitwise-AND request into current independently for the period and active_duration fields.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33 (GPIO/PWM_OUT row, evt[2:0]=010b: \"The 'byte_msg_payload' bitwise AND 'current interface status' is written to the interface\"), TC18.txt L4098-4100", + "tc18_master_id": "TC18-13.5-001", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/pwm.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/pwm.hpp / tests/test_pwm.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-PWM-004 (\"PWM_OUT write semantics: Reserved and Reconfigure rejected\"). Genuinely implemented+tested: rcp::pwm::apply_write_field(WriteSemantics::And, ...) (include/rcp/pwm.hpp) bitwise-ANDs current and operand -- tests/test_pwm.cpp's \"apply_write_field applies Or/And/Xor\" TEST_CASE (tagged [REQ-PWM-003], this catalog's own bundled Or/And/Xor/Add/Subtract entry, which textually covers AND among the five combinators it describes) exercises the AND case directly." + }, + { + "id": "REQ-PWM-005", + "title": "rcp_ep_pwm_out_apply_write() implements RCP_EP_PWM_OUT_WRITE_XOR per field", + "text": "rcp_ep_pwm_out_apply_write() shall, for evt == RCP_EP_PWM_OUT_WRITE_XOR, bitwise-XOR request into current independently for the period and active_duration fields.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33 (GPIO/PWM_OUT row, evt[2:0]=011b: \"The 'byte_msg_payload' bitwise XOR 'current interface status' is written to the interface\"), TC18.txt L4102-4104", + "tc18_master_id": "TC18-13.5-001", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/pwm.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/pwm.hpp / tests/test_pwm.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-PWM-005 (\"PWM_IN response-only read model and PWM_IN_NO_SIGNAL\"). Genuinely implemented+tested: rcp::pwm::apply_write_field(WriteSemantics::Xor, ...) (include/rcp/pwm.hpp) bitwise-XORs current and operand -- the same \"apply_write_field applies Or/And/Xor\" TEST_CASE (tagged [REQ-PWM-003]) exercises the XOR case directly." + }, + { + "id": "REQ-PWM-006", + "title": "rcp_ep_pwm_out_apply_write() implements RCP_EP_PWM_OUT_WRITE_ADD with per-field 16-bit saturation", + "text": "rcp_ep_pwm_out_apply_write() shall, for evt == RCP_EP_PWM_OUT_WRITE_ADD, add request to current independently for the period and active_duration fields, each saturating at 0xFFFF rather than wrapping or carrying into the other field.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33 (GPIO/PWM_OUT row, evt[2:0]=101b: \"The 'byte_msg_payload' plus 'current interface status' is written to the interface\"), TC18.txt L4108-4109; saturation rule, TC18.txt L4118-4119", + "tc18_master_id": "TC18-13.5-003", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/pwm.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/pwm.hpp / tests/test_pwm.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-PWM-006 (\"PWM_IN rising/falling edge trigger signals (Table 44)\"). Genuinely implemented+tested: rcp::pwm::apply_write_field(WriteSemantics::Add, ...) (include/rcp/pwm.hpp) adds current and operand, saturating at 0xFFFF (uint16_t width, independent of GPIO's own 32-bit bound) -- tests/test_pwm.cpp's \"apply_write_field Add saturates at 0xFFFF, not 0xFFFFFFFF\" TEST_CASE and \"apply_write applies saturating Add/Subtract per field, independently of GPIO's own bound\" (both bracket-tagged [REQ-PWM-006] already -- note this numeral coincidentally matches c-RCP's own REQ-PWM-006 id even though this catalog's own pre-existing REQ-PWM-006 entry describes unrelated PWM_IN trigger-signal content, whose real coverage has itself since moved to REQ-PWM-032/033/034; left untouched here per the collision-avoidance policy, not itself re-filed as a separate finding) exercise the saturation boundary." + }, + { + "id": "REQ-PWM-007", + "title": "rcp_ep_pwm_out_apply_write() implements RCP_EP_PWM_OUT_WRITE_SUB as request minus current with per-field 16-bit saturation", + "text": "rcp_ep_pwm_out_apply_write() shall, for evt == RCP_EP_PWM_OUT_WRITE_SUB, subtract current from request independently for the period and active_duration fields, each saturating at 0x0000 rather than wrapping.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33 (GPIO/PWM_OUT row, evt[2:0]=110b: \"'byte_msg_payload' minus 'current interface status' is written as is to interface\"), TC18.txt L4111-4112; saturation rule, TC18.txt L4118-4119", + "tc18_master_id": "TC18-13.5-003", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/pwm.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/pwm.hpp / tests/test_pwm.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-PWM-007 (\"PwmErrc is a distinct error category with a non-empty message\"). Genuinely implemented+tested: rcp::pwm::apply_write_field(WriteSemantics::Subtract, ...) (include/rcp/pwm.hpp) computes operand minus current, saturating at 0 (request MINUS current, per Table 33's own wording -- REQ-PWM-007 regression fix) -- tests/test_pwm.cpp's \"apply_write_field Subtract computes request minus current (REQ-PWM-007 regression)\"/\"apply_write_field Subtract saturates at 0 when current exceeds request\" TEST_CASEs (bracket-tagged [REQ-PWM-007] already -- same coincidental-numeral note as REQ-PWM-006's own collision entry: this catalog's own pre-existing REQ-PWM-007 entry describes unrelated PwmErrc-category content) exercise both the operand-order fix and the saturation boundary." + }, + { + "id": "REQ-PWM-008", + "title": "rcp_ep_pwm_out_apply_write() treats RCP_EP_PWM_OUT_WRITE_RESERVED4 as a no-op", + "text": "IMPLEMENTED (FIXED 2026-08-14, issue #426; dispatch-wiring gap closed 2026-08-16, issue #469): rcp_ep_pwm_out_apply_write() returns current unchanged for evt == RCP_EP_PWM_OUT_WRITE_RESERVED4 (the 'ignored' half of Table 33's two-part reserved-value rule); rcp_ep_pwm_out_decode_write_request() now also returns the new RCP_EP_PWM_OUT_ERR_RESERVED_EVT for that same evt value, which the new rcp_ep_pwm_out_wire_error() maps to RCP_ERROR_UNSUPPORTED_CMD, closing the previously-missing 'an err-response with error code = UNSUPPORTED_CMD shall be sent' half. That mapping function itself, though directly unit-tested since #426, had no caller anywhere outside its own unit tests -- not even PWM_OUT's own real dispatch path, which did not previously exist in test_tc18_gaps_ep.c at all. Issue #469 closed that: the new pwm_out_dispatch_handler() (an rcp_mock_endpoint_handler_fn registered via the existing, unmodified rcp_mock_server_add_endpoint(), mirroring gpio_dispatch_handler()'s own identical fix) now calls rcp_ep_pwm_out_wire_error() on every rejected write and builds the required err-response via rcp_acf_build_error_response() when it returns non-NONE, proven end-to-end by test_pwm_out_dispatch_reserved_evt_write_gets_unsupported_cmd_error_response().", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33 (GPIO/PWM_OUT row, evt[2:0]=100b: \"reserved -request shall be ignored and an err-response with error code = UNSUPPORTED_CMD shall be sent\"), TC18.txt L4106-4107", + "tc18_master_id": "TC18-13.5-001", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/pwm.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/pwm.hpp / tests/test_pwm.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-PWM-008 (\"PwmInEndpoint::handle_request applies Table 33 Row 2 evt[2:0] classification before reading\"). Genuinely implemented+tested: rcp::pwm::apply_write() (include/rcp/pwm.hpp) leaves period/active_duration unchanged for evt==WriteSemantics::Reserved (the \"ignored\" no-op half of Table 33's two-part reserved-value rule) -- tests/test_pwm.cpp's \"apply_write's duty-cycle cap applies even for Reserved/Reconfigure's unchanged fields\" TEST_CASE (tagged [REQ-PWM-056]) confirms period stays unchanged for Reserved. The wire-decode \"err-response with UNSUPPORTED_CMD\" half is covered by \"PWM_OUT decode_write_request rejects evt[2:0]==100b (Reserved) without populating outputs\" (bracket-tagged [REQ-PWM-008] already -- same coincidental-numeral note as REQ-PWM-006/007's own collision entries: this catalog's own pre-existing REQ-PWM-008 entry describes unrelated PwmInEndpoint::handle_request Row-2-classification content, itself carrying severity:cybersecurity, left untouched here) which asserts PwmErrc::reserved_evt and its wire_error() mapping to UnsupportedCmd." + }, + { + "id": "REQ-PWM-009", + "title": "rcp_ep_pwm_out_apply_write() fails safe for a misrouted RCP_EP_PWM_OUT_WRITE_RECONFIG", + "text": "rcp_ep_pwm_out_apply_write() shall return current unchanged for evt == RCP_EP_PWM_OUT_WRITE_RECONFIG, since callers must route that value to rcp_ep_pwm_out_apply_reconfig() instead.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33 (GPIO/PWM_OUT row, evt[2:0]=111b: \"The byte_msg_payload is not presented to the interface but used to change the configuration of the endpoint (see 12.7.1).\"), TC18.txt L4114-4115", + "tc18_master_id": "TC18-13.5-001", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 9, include/rcp/pwm.hpp module). The behavior itself is genuinely implemented and tested in include/rcp/pwm.hpp / tests/test_pwm.cpp. The blocker is that cpp-RCP's pre-existing catalog range for this low id predates this rewrite's later convention of reusing c-RCP's exact ids: this specific id was already assigned, by file order at the time, to an unrelated pre-rewrite requirement, and this id is already taken in .fusa-reqs.json by a materially different, already-catalogued requirement. Adding a second, conflicting entry under the same id would corrupt the catalog's own id uniqueness and is not attempted here. Filed so a future renumbering-cleanup batch (out of this batch's own scope) can resolve the collision and migrate this entry in. Already taken by: this catalog's own REQ-PWM-009 (\"PwmInEndpoint::handle_request reports config-write (evt[2:0]==111b) as not yet supported\"). Genuinely implemented+tested: rcp::pwm::apply_write() (include/rcp/pwm.hpp) returns current unchanged for evt==WriteSemantics::Reconfigure (callers must route that value to apply_reconfig() instead) -- tests/test_pwm.cpp's \"apply_write leaves state unchanged for Reconfigure (fail-safe)\" TEST_CASE (bracket-tagged [REQ-PWM-009] already -- same coincidental-numeral note: this catalog's own pre-existing REQ-PWM-009 entry describes unrelated PwmInEndpoint::handle_request config-write-not-supported content) exercises exactly this." } ] } diff --git a/.fusa-reqs.json b/.fusa-reqs.json index c2116cb..bae17dd 100644 --- a/.fusa-reqs.json +++ b/.fusa-reqs.json @@ -7998,6 +7998,1029 @@ "status": "implemented", "tc18": "§12.7.1 Configuration of endpoints, TC18.txt L2463-2484", "tc18_master_id": "TC18-12.7.1-003" + }, + { + "id": "REQ-MDIO-008", + "title": "rcp_ep_mdio_unpack_word_at() reads one packed register word by index", + "text": "rcp_ep_mdio_unpack_word_at() shall return rcp_ep_mdio_word_decode() applied to data[2*word_index .. 2*word_index+2). NOTE (2026-08-10, c-RCP-AUDIT-06, issue #256 Group D): a pure index-into-packed-words helper over this module's own word-packing layout -- see REQ-MDIO-002/003's own notes. Corrected from carrying no citation at all to an honestly-cited entry.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.1, TC18.txt L6033-6037 (cited only as attribution for which general topic area motivated this endpoint type's existence; see REQ-MDIO-002/003/005)" + }, + { + "id": "REQ-MDIO-009", + "title": "rcp_ep_mdio_functional_cfg_init() zero-initializes an MDIO functional config", + "text": "rcp_ep_mdio_functional_cfg_init() shall zero-initialize cfg and initialize cfg->common via rcp_regmap_ep_functional_cfg_init(), leaving every common flag false.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-MDIO-010", + "title": "rcp_ep_mdio_functional_cfg_writable() delegates to the shared field-authorization logic", + "text": "rcp_ep_mdio_functional_cfg_writable() shall return rcp_server_field_writable(state, RCP_LIFECYCLE_FIELD_FUNCTIONAL_W, writer).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.2/.3, TC18.txt L2553-2554, L2601-2602 -- §12.3.1.3 W* marker convention, TC18.txt L2601-2602 (same delegate-function citation basis as REQ-WAKEUP-002)" + }, + { + "id": "REQ-MDIO-011", + "title": "rcp_ep_mdio_strerror() returns a non-NULL message for every error code", + "text": "rcp_ep_mdio_strerror() shall return a non-NULL, non-empty, distinct message for each rcp_ep_mdio_errc_t value, and a non-NULL message for any unrecognized value.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-MDIO-012", + "title": "rcp_ep_mdio_encode_read_request() encodes this module's own ACF_ABB MDIO read request payload", + "text": "rcp_ep_mdio_encode_read_request() shall return a zeroed rcp_bytes_t when !rcp_ep_mdio_addr_valid(addr) or word_count is 0 or exceeds RCP_EP_MDIO_MAX_BURST_WORDS, and otherwise encode an ACF_ABB message with op RCP_ACF_OP_READ whose payload is a leading mdio_mode octet (REQ-MDIO-021) followed by addr's clause/prtad/devad/regad fields and word_count, all as specified. NOTE (2026-08-10, c-RCP-AUDIT-06, issue #256 Group D; UPDATED 2026-08-12, issue #201): this payload layout is this module's own original design (mdio_mode + clause/prtad/devad/regad/word_count) for the address portion, NOT TC18 §13.7.13.3 Figure 43/Table 60's own unspecified mdio_address wire width -- see REQ-MDIO-021, now PARTIAL: the mdio_mode field itself is real and wire-encoded, closing that half of the original gap, but the address portion's own exact bit layout remains a documented, still-open remainder (REQ-MDIO-021's own text). This entry's own function is correctly implemented against its own documented contract.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Figure 43/Table 60, TC18.txt L6065-6088 -- the real TC18 wire layout this function's own payload does not match; see REQ-MDIO-021", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-013", + "title": "rcp_ep_mdio_decode_read_request() validates and decodes this module's own ACF-level MDIO read request payload", + "text": "rcp_ep_mdio_decode_read_request() shall return RCP_EP_MDIO_ERR_SHORT_FRAME for a frame shorter than the ACF_ABB header, its declared payload, or the 8-byte (mdio_mode octet + 7-byte address/word_count) request prefix; RCP_EP_MDIO_ERR_BAD_MSG_TYPE for a non-ACF_ABB frame; RCP_EP_MDIO_ERR_WRONG_BUS for a mismatched byte_bus_id; RCP_EP_MDIO_ERR_WRONG_OP for an op other than RCP_ACF_OP_READ; RCP_EP_MDIO_ERR_UNSUPPORTED_MMS when the decoded mdio_mode octet is an MMS value (REQ-MDIO-021's own still-open remainder); RCP_EP_MDIO_ERR_BAD_EVT when evt[2:0] is not 0b000 (the value REQ-ACF-023 resolves, after cross-checking TC18's own Figure 33 worked example, as the legal plain-request value for this Table 33 row -- see that entry for the full resolution of Table 33's own apparent internal inconsistency); RCP_EP_MDIO_ERR_BAD_ADDR when the decoded address fails rcp_ep_mdio_addr_valid(); RCP_EP_MDIO_ERR_BAD_WORD_COUNT when the decoded word_count is 0 or exceeds RCP_EP_MDIO_MAX_BURST_WORDS; and otherwise RCP_EP_MDIO_OK with the address, word count, and transaction number populated. NOTE (2026-08-10, c-RCP-AUDIT-06, issue #256 Group D; UPDATED 2026-08-12, issue #201): the address portion's own payload layout this decodes is this module's own original design, not TC18's own unspecified wire width -- see REQ-MDIO-012's own note and REQ-MDIO-021 (now PARTIAL).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L4069-4116 (evt[2:0] legality, resolved at REQ-ACF-023); §13.7.13.3 Figure 43/Table 60, TC18.txt L6065-6088 (the real wire layout this function's own payload does not match; see REQ-MDIO-021)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-014", + "title": "rcp_ep_mdio_encode_read_response() encodes timed and untimed MDIO read responses using this module's own packed-words payload", + "text": "rcp_ep_mdio_encode_read_response() shall return a zeroed rcp_bytes_t when word_count exceeds RCP_EP_MDIO_MAX_BURST_WORDS or on allocation failure, and otherwise, when timed is false, encode an ACF_ABB frame with op RCP_ACF_OP_READ, rsp=1, and payload rcp_ep_mdio_pack_words(words, word_count). NOTE (2026-08-18, c-RCP-18-tracker, issue #533 Group 2 REQ-MDIO-* batch): split off this function's own ACF_GBB/timed=true clause, now REQ-MDIO-025 -- the same ACF_ABB/ACF_GBB dual-format bundling the REQ-ACF-* batch (issue #533 Group 1) already established as splittable (REQ-ACF-004/-038, -005/-039, -006/-040, -009/-041, -010/-042/-043, -014/-044, -015/-045).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Figure 43/Table 60, TC18.txt L6065-6088 (the real TC18 mdio_payload field this response's own packed-word layout does not literally match in framing, though the underlying 16/32-bit register data is the same concept; see REQ-MDIO-021)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-015", + "title": "rcp_ep_mdio_decode_read_response() validates and decodes either ACF_ABB or ACF_GBB MDIO read responses in this module's own packed-words layout", + "text": "rcp_ep_mdio_decode_read_response() shall, for an ACF_ABB frame, return RCP_EP_MDIO_ERR_SHORT_FRAME for a frame too short for the ACF_ABB header or its declared payload, RCP_EP_MDIO_ERR_WRONG_BUS for a mismatched byte_bus_id, RCP_EP_MDIO_ERR_BAD_WORD_COUNT for an odd payload length or more than RCP_EP_MDIO_MAX_BURST_WORDS words, and otherwise RCP_EP_MDIO_OK with the packed word bytes, word count, and transaction number populated, *out_timed false and *out_timestamp 0. NOTE (2026-08-18, c-RCP-18-tracker, issue #533 Group 2 REQ-MDIO-* batch): split off this function's own ACF_GBB decode path (now REQ-MDIO-026), matching REQ-MDIO-014/-025's own encode-side split and the REQ-ACF-* batch's ABB/GBB precedent.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Figure 43/Table 60, TC18.txt L6065-6088 (see REQ-MDIO-021)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-016", + "title": "rcp_ep_mdio_encode_write_request() encodes this module's own ACF_ABB MDIO write request payload", + "text": "rcp_ep_mdio_encode_write_request() shall return a zeroed rcp_bytes_t when !rcp_ep_mdio_addr_valid(addr), word_count is 0 or exceeds RCP_EP_MDIO_MAX_BURST_WORDS, or on allocation failure, and otherwise encode an ACF_ABB message with op RCP_ACF_OP_WRITE whose payload is a leading mdio_mode octet (REQ-MDIO-021) followed by addr's clause/prtad/devad/regad fields and rcp_ep_mdio_pack_words(words, word_count). NOTE (2026-08-10, c-RCP-AUDIT-06, issue #256 Group D; UPDATED 2026-08-12, issue #201): the write-side counterpart of REQ-MDIO-012 -- see that entry's own note and REQ-MDIO-021 (now PARTIAL) for this payload layout's basis.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Figure 43/Table 60, TC18.txt L6065-6088 (see REQ-MDIO-021)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-017", + "title": "rcp_ep_mdio_decode_write_request() validates and decodes this module's own ACF-level MDIO write request payload", + "text": "rcp_ep_mdio_decode_write_request() shall return RCP_EP_MDIO_ERR_SHORT_FRAME for a frame shorter than the ACF_ABB header, its declared payload, or the 6-byte (mdio_mode octet + 5-byte address prefix) request prefix; RCP_EP_MDIO_ERR_BAD_MSG_TYPE for a non-ACF_ABB frame; RCP_EP_MDIO_ERR_WRONG_BUS for a mismatched byte_bus_id; RCP_EP_MDIO_ERR_WRONG_OP for an op other than RCP_ACF_OP_WRITE; RCP_EP_MDIO_ERR_UNSUPPORTED_MMS when the decoded mdio_mode octet is an MMS value (REQ-MDIO-021's own still-open remainder); RCP_EP_MDIO_ERR_BAD_EVT when evt[2:0] is not 0b000 (the value REQ-ACF-023 resolves, after cross-checking TC18's own Figure 33 worked example, as the legal plain-request value for this Table 33 row -- see that entry for the full resolution of Table 33's own apparent internal inconsistency); RCP_EP_MDIO_ERR_BAD_ADDR when the decoded address fails rcp_ep_mdio_addr_valid(); RCP_EP_MDIO_ERR_BAD_WORD_COUNT when the trailing words region's byte length is odd, is 0, or represents more than RCP_EP_MDIO_MAX_BURST_WORDS words; and otherwise RCP_EP_MDIO_OK with the address, packed word bytes, word count, and transaction number populated. NOTE (2026-08-10, c-RCP-AUDIT-06, issue #256 Group D; UPDATED 2026-08-12, issue #201): the address portion's own payload layout this decodes is this module's own original design, not TC18's own unspecified wire width -- see REQ-MDIO-016's own note and REQ-MDIO-021 (now PARTIAL).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L4069-4116 (evt[2:0] legality, resolved at REQ-ACF-023); §13.7.13.3 Figure 43/Table 60, TC18.txt L6065-6088 (see REQ-MDIO-021)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-018", + "title": "rcp_ep_mdio_encode_write_response() encodes timed and untimed MDIO write responses using this module's own packed-words payload", + "text": "rcp_ep_mdio_encode_write_response() shall return a zeroed rcp_bytes_t when accepted_word_count exceeds RCP_EP_MDIO_MAX_BURST_WORDS or on allocation failure, and otherwise, when timed is false, encode an ACF_ABB frame with op RCP_ACF_OP_WRITE, rsp=1, and payload rcp_ep_mdio_pack_words(accepted_words, accepted_word_count). NOTE (2026-08-18, c-RCP-18-tracker, issue #533 Group 2 REQ-MDIO-* batch): split off this function's own ACF_GBB/timed=true clause, now REQ-MDIO-027 -- the write-response counterpart of REQ-MDIO-014/-025's own split.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Figure 43/Table 60, TC18.txt L6065-6088 (see REQ-MDIO-021)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-019", + "title": "rcp_ep_mdio_decode_write_response() validates and decodes either ACF_ABB or ACF_GBB MDIO write responses in this module's own packed-words layout", + "text": "rcp_ep_mdio_decode_write_response() shall, for an ACF_ABB frame, return RCP_EP_MDIO_ERR_SHORT_FRAME for a frame too short for the ACF_ABB header or its declared payload, RCP_EP_MDIO_ERR_WRONG_BUS for a mismatched byte_bus_id, RCP_EP_MDIO_ERR_BAD_WORD_COUNT for an odd payload length or more than RCP_EP_MDIO_MAX_BURST_WORDS words, and otherwise RCP_EP_MDIO_OK with the accepted packed word bytes, word count, and transaction number populated, *out_timed false and *out_timestamp 0. NOTE (2026-08-18, c-RCP-18-tracker, issue #533 Group 2 REQ-MDIO-* batch): split off this function's own ACF_GBB decode path (now REQ-MDIO-028) -- the write-response counterpart of REQ-MDIO-015/-026's own split.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Figure 43/Table 60, TC18.txt L6065-6088 (see REQ-MDIO-021)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-020", + "title": "The MDIO EP has no configurable parameters beyond the common block, but still exposes mdio_ep_len and mdio_ep_status", + "text": "IMPLEMENTED (FIXED 2026-08-11, c-RCP-AUDIT-06, issue #256 Group I): c-RCP correctly gives the MDIO endpoint no endpoint-specific *configurable* parameters, matching TC18 §13.7.13.2's 'The MDIO EP does not have any configurable parameters' — that statement describes what a write can change, not whether the block is readable. Table 59's three register rows are now all reachable via the generic evt[2:0]=111b register-block mechanism: mdio_ep_len (0x0000, 8 bit, R), the reserved octet at 0x0001 (8 bit, R, reads 0x00), and mdio_ep_status (0x0004, 16 bit, R/W, contents still to be defined by the specification — c-RCP round-trips whatever value is written, since the specification itself defines no interpretation). A genuine address-collision editorial defect, the fifth found this audit (after ep_pwm.h's/ep_gpio.h's/ep_i2c.h's/ep_iseled.h's own): Table 59 printed mdio_ep_status at the same address (0x0002) as mdio_ep_enable&clr; corrected to 0x0004, the next unclaimed offset after the common options octet, since Table 59 defines no base_clk row the way every other endpoint type's own table does (RCP_EP_MDIO_EP_FUNC_LEN = 0x0006, one register width narrower than the common case). New rcp_ep_mdio_render_registers()/_apply_reconfig()/_reconfig_strerror()/_encode_reconfig_request() implement the same generic addressed-write mechanism PWM_OUT/GPIO/SPI/I2C/UART/LIN/ADC/PWM_IN/ISELED already had — MDIO is now 9 of 11 endpoint types with it. rcp_ep_mdio_functional_cfg_t gains ep_status (the only field this module adds; still no set_ep_status() mutator, matching every register-block field in every other endpoint type -- reachable only via rcp_ep_mdio_apply_reconfig()).", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.2 Table 59, TC18.txt L6045 and L6047-6056", + "tc18_master_id": "TC18-13.7.13.2-002" + }, + { + "id": "REQ-MDIO-023", + "title": "MDIO EP_func register block reachable via evt[2:0]=111b (Table 59, address-collision defect corrected)", + "text": "IMPLEMENTED (FIXED 2026-08-11, c-RCP-AUDIT-06, issue #256 Group I): rcp_ep_mdio_decode_read_request()/_decode_write_request() already correctly rejected evt[2:0]=111b (RCP_EP_MDIO_ERR_BAD_EVT, via acf.h's rcp_acf_evt_row2_is_plain()), but no counterpart implemented that §12.7.1 configuration-write path at all — no rcp_ep_mdio_apply_reconfig() existed. See REQ-MDIO-020 for the register block's own content and the address-collision defect this entry's fix shares credit for; this entry tracks the mechanism itself (rcp_ep_mdio_render_registers()/_apply_reconfig()/_reconfig_strerror()/_encode_reconfig_request()), mirroring every other Group I register-block fix's own \"mechanism gets its own id, content gets the pre-existing one\" convention (REQ-PWM-058/059, REQ-ISELED-026/027/029).", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.2 Table 59, TC18.txt L6045 and L6047-6056", + "tc18_master_id": "TC18-13.7.13.2-002" + }, + { + "id": "REQ-MDIO-024", + "title": "mdio_address's own bit layout for MMS addressing (4-bit MMS selector + 16-bit register address)", + "text": "PARTIAL, NEW 2026-08-13 (issue #335 lineage): the requirement this catalog's own audit lineage first surfaced as spec-defects-report item 55 -- TC18 §13.7.13.3 neither Figure 43 nor Table 60 gives `mdio_address` a bit width or internal layout for MMS mode, only \"as per IEEE & OA SPI spec\" -- remains genuinely unresolved by TC18 itself (item 55 stays open, still worth the committee's attention). Per user direction, this fix works around the gap with a real, externally-sourced (not invented from nothing) assumption: a web search located the actual OPEN Alliance 10BASE-T1x MAC-PHY Serial Interface specification, V1.1, stored at /Users/matt/Documents/Coding/SoundMatt/OPEN_Alliance_10BASE-T1x_MAC-PHY_Serial_Interface_V1.1.pdf (public OPEN Alliance document, NOT the confidential TC18 document, NOT in this repo). Its own control command header (§7.4.1 Table 4) shows the real protocol \"MMS\" terminology is almost certainly borrowed from: a 4-bit MMS selector (0-15, its own §9.1 Table 6) immediately followed by a 16-bit ADDR field. rcp_ep_mdio_mms_addr_t (ep_mdio.h) ASSUMES TC18's own mdio_address field packs the same two sub-fields in the same order, represented on THIS module's own wire as two whole octets (mms, then big-endian addr) -- the same give-every-sub-field-its-own-octet convention the pre-existing MMD prefix already uses for prtad/devad. Catalogued PARTIAL, not IMPLEMENTED: the code path fully exists and is fully tested against ITS OWN assumed layout, but if the real TC18 committee resolution of item 55 differs (different field order, different width, or `mdio_address` meaning something else for MMS entirely), a peer built against this assumption will not interoperate with one built against the real resolution. One further honesty note: the external OA-SPI spec's own Table 6 marks MMS1's register width \"implementation dependent\", not literally 32-bit -- REQ-MDIO-022's own 32-bit-for-MMS0/1 rule is TC18's own overriding convention for RCP's purposes, not simply quoted from the external spec; that part is NOT this assumption's own uncertainty.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18-gap", + "status": "partial", + "tc18": "§13.7.13.3 Figure 43 and Table 60, TC18.txt L6065-6088 (mdio_address itself unspecified -- TC18_spec_defects_report.md item 55; this entry's own implementation is a documented external-spec-informed assumption, not TC18-derived)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-021", + "title": "the 2-bit mdio_mode selector and the Figure 43 request payload layout", + "text": "IMPLEMENTED (2026-08-13, closes the remainder left PARTIAL by the 2026-08-12 fix): all 4 mdio_mode values (TC18 §13.7.13.3 Table 60) are now both decodable AND fully interpretable -- MMD (00b/01b, unchanged since the prior fix) via the existing rcp_ep_mdio_addr_t family, and MMS (10b/11b) via the new rcp_ep_mdio_mms_addr_t family (rcp_ep_mdio_encode_mms_read_request()/_decode_mms_read_request() and the write/response equivalents, ep_mdio.h). The mdio_mode octet's own wire encoding (leading byte, bits[1:0]) and the 00b-assigned-to-MMD-single documented assumption are unchanged from the prior fix. See REQ-MDIO-024 for the new, separately-tracked assumption MMS interpretation itself rests on (mdio_address's own bit layout, which TC18 still does not specify -- spec-defects-report item 55 remains open). RCP_EP_MDIO_ERR_UNSUPPORTED_MMS keeps its name (source compatibility) but now means \"this frame belongs to the *_mms_* family, use that decoder instead\" rather than \"MMS is unsupported\" -- the mirror-image RCP_EP_MDIO_ERR_WRONG_MDIO_MODE is new, returned by the *_mms_* decoders for an MMD-mode frame.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Figure 43 and Table 60, TC18.txt L6065-6088 (citation-drift fix, same lineage as issue #341: RC1's own Figure 42/Table 57 are RC5's own Figure 43/Table 60)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-022", + "title": "MMS0 and MMS1 carry 32-bit data fields, not 16-bit", + "text": "IMPLEMENTED (2026-08-13, issue #335 lineage, user-directed after confirming this was genuinely blocked without an external spec): TC18 §13.7.13.3 Table 60's own explicit, non-assumption rule -- MMS0 and MMS1 use 32-bit data fields, every other MMS uses 16-bit -- is implemented by rcp_ep_mdio_mms_uses_32bit_words() (ep_mdio.h/.c), consulted by the new rcp_ep_mdio_mms_pack_words()/_mms_word_count_of()/_mms_unpack_word_at() family (uint32_t-typed words at the API boundary, zero-extended for a 16-bit mms; rcp_ep_mdio_word32_encode()/_decode() for the 32-bit wire representation itself, mirroring the pre-existing 16-bit rcp_ep_mdio_word_encode()/_decode()). The pre-existing MMD-family word codec (rcp_ep_mdio_word_encode() etc.) is completely unchanged -- it was never wrong, it always correctly modeled MMD's own unconditional 16-bit width; this fix adds a second, MMS-specific codec rather than modifying it. This requirement's own rule is now reachable in practice because REQ-MDIO-024 (new) supplies MMS addressing itself, via a documented, externally-sourced (not invented) assumption -- see that entry for the caveat this requirement's own implementation depends on.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Table 60, TC18.txt L6086 (citation-drift fix, same lineage as issue #341: RC1's own Table 57 is RC5's own Table 60)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-025", + "title": "rcp_ep_mdio_encode_read_response() encodes a timed MDIO read response as an ACF_GBB frame", + "text": "rcp_ep_mdio_encode_read_response() shall, when timed is true, encode an ACF_GBB frame with message_timestamp set to timestamp, mtv RCP_ACF_MTV_VALID, op RCP_ACF_OP_READ, rsp=1, and payload rcp_ep_mdio_pack_words(words, word_count) (subject to REQ-MDIO-014's own word_count/allocation-failure guard, which applies identically to both the ACF_ABB and ACF_GBB paths). NEW 2026-08-18 (c-RCP-18-tracker, issue #533 Group 2 REQ-MDIO-* batch): split off REQ-MDIO-014's own original text, which bundled the ACF_ABB (untimed) and ACF_GBB (timed) encodings of one function under a single id -- the same ABB/GBB dual-format bundling pattern the REQ-ACF-* batch (issue #533 Group 1) already established as splittable.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Figure 43/Table 60, TC18.txt L6065-6088 (the real TC18 mdio_payload field this response's own packed-word layout does not literally match in framing, though the underlying 16/32-bit register data is the same concept; see REQ-MDIO-021)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-026", + "title": "rcp_ep_mdio_decode_read_response() validates and decodes an ACF_GBB MDIO read response", + "text": "rcp_ep_mdio_decode_read_response() shall, for an ACF_GBB frame, return RCP_EP_MDIO_ERR_SHORT_FRAME for a frame too short for the ACF_GBB header or its declared payload, RCP_EP_MDIO_ERR_WRONG_BUS for a mismatched byte_bus_id, RCP_EP_MDIO_ERR_BAD_WORD_COUNT for an odd payload length or more than RCP_EP_MDIO_MAX_BURST_WORDS words, and otherwise RCP_EP_MDIO_OK with the packed word bytes, word count, and transaction number populated, *out_timed and *out_timestamp set per rcp_acf_gbb_is_timed()/the frame's own message_timestamp. NEW 2026-08-18 (c-RCP-18-tracker, issue #533 Group 2 REQ-MDIO-* batch): split off REQ-MDIO-015's own original text, which bundled the ACF_ABB and ACF_GBB decode paths of one function under a single id -- see REQ-MDIO-014/-025's own note for the same pattern on the encode side.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Figure 43/Table 60, TC18.txt L6065-6088 (see REQ-MDIO-021)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-027", + "title": "rcp_ep_mdio_encode_write_response() encodes a timed MDIO write response as an ACF_GBB frame", + "text": "rcp_ep_mdio_encode_write_response() shall, when timed is true, encode an ACF_GBB frame with message_timestamp set to timestamp, mtv RCP_ACF_MTV_VALID, op RCP_ACF_OP_WRITE, rsp=1, and payload rcp_ep_mdio_pack_words(accepted_words, accepted_word_count) (subject to REQ-MDIO-018's own accepted_word_count/allocation-failure guard, which applies identically to both the ACF_ABB and ACF_GBB paths). NEW 2026-08-18 (c-RCP-18-tracker, issue #533 Group 2 REQ-MDIO-* batch): split off REQ-MDIO-018's own original text -- the write-response counterpart of REQ-MDIO-014/-025's own split; see that entry's note for the shared ABB/GBB precedent (REQ-ACF-*, issue #533 Group 1).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Figure 43/Table 60, TC18.txt L6065-6088 (see REQ-MDIO-021)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-MDIO-028", + "title": "rcp_ep_mdio_decode_write_response() validates and decodes an ACF_GBB MDIO write response", + "text": "rcp_ep_mdio_decode_write_response() shall, for an ACF_GBB frame, return RCP_EP_MDIO_ERR_SHORT_FRAME for a frame too short for the ACF_GBB header or its declared payload, RCP_EP_MDIO_ERR_WRONG_BUS for a mismatched byte_bus_id, RCP_EP_MDIO_ERR_BAD_WORD_COUNT for an odd payload length or more than RCP_EP_MDIO_MAX_BURST_WORDS words, and otherwise RCP_EP_MDIO_OK with the accepted packed word bytes, word count, and transaction number populated, *out_timed and *out_timestamp set per rcp_acf_gbb_is_timed()/the frame's own message_timestamp. NEW 2026-08-18 (c-RCP-18-tracker, issue #533 Group 2 REQ-MDIO-* batch): split off REQ-MDIO-019's own original text -- the write-response counterpart of REQ-MDIO-015/-026's own split; see that entry's note for the shared ABB/GBB precedent (REQ-ACF-*, issue #533 Group 1).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.13.3 Figure 43/Table 60, TC18.txt L6065-6088 (see REQ-MDIO-021)", + "tc18_master_id": "TC18-13.7.13.3-002" + }, + { + "id": "REQ-PWM-010", + "title": "rcp_ep_pwm_out_apply_reconfig() applies an addressed write into the PWM_OUT EP_func register block", + "text": "rcp_ep_pwm_out_apply_reconfig() shall interpret its payload as a 16-bit big-endian relative start address followed by configuration data octets, and shall write those octets into cfg's EP_func registers from that address onward, leaving read-only registers (EP_LEN, the reserved octet, base_clk) unchanged while still applying the rest of the addressed span, and shall return RCP_EP_PWM_OUT_RECONFIG_OK.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.2 Table 46 (pwmo functional configuration register block), TC18.txt L4967-5012", + "tc18_master_id": "TC18-13.7.5.2-001" + }, + { + "id": "REQ-PWM-011", + "title": "rcp_ep_pwm_out_apply_reconfig() ignores a configuration write with no address+data", + "text": "rcp_ep_pwm_out_apply_reconfig() shall return RCP_EP_PWM_OUT_RECONFIG_ERR_SHORT when the payload does not carry a 2-octet address plus at least one data octet, leaving cfg entirely unchanged. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of this entry's own previously-bundled text, which also asserted the ERR_OUT_OF_RANGE case now REQ-PWM-060's own separate id -- two distinct error conditions, each triggered by a different malformed payload, the same per-outcome split REQ-PWM-002..009 already establishes for a single switch's separate arms.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.2 Table 46 (pwmo functional configuration register block, pwmo_ep_len fixed at 0x06), TC18.txt L4967-5012", + "tc18_master_id": "TC18-13.7.5.2-001" + }, + { + "id": "REQ-PWM-060", + "title": "rcp_ep_pwm_out_apply_reconfig() ignores a configuration write that extends past EP_LEN", + "text": "rcp_ep_pwm_out_apply_reconfig() shall return RCP_EP_PWM_OUT_RECONFIG_ERR_OUT_OF_RANGE when start_address plus the data length exceeds RCP_EP_PWM_OUT_EP_FUNC_LEN, leaving cfg entirely unchanged. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-011, whose own text previously bundled this out-of-range case with the short-payload case under one id -- see REQ-PWM-011's own text for the split rationale.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.2 Table 46 (pwmo functional configuration register block, pwmo_ep_len fixed at 0x06), TC18.txt L4967-5012", + "tc18_master_id": "TC18-13.7.5.2-001" + }, + { + "id": "REQ-PWM-012", + "title": "rcp_ep_pwm_out_trigger_fires() never fires for RCP_EP_PWM_OUT_TRIGGER_NONE", + "text": "rcp_ep_pwm_out_trigger_fires() shall return false for trigger == RCP_EP_PWM_OUT_TRIGGER_NONE regardless of event. CLARIFIED (2026-08-10, c-RCP-AUDIT-06, issue #256 Group C): NONE is this module's own original addition -- TC18 Table 45 documents three fixed, always-on trigger signals with no off/none state, and Table 46 defines no client-selectable register for choosing among them at all. See ep_pwm.h's own file header for the full clarification.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.1 Table 45 (\"A PWM endpoint creates three trigger events\"), TC18.txt L4939-4947 -- names three fixed hardware signals, not a client-configurable field; Table 46 (pwmo functional configuration), TC18.txt L4967-5012, defines no trigger-select register", + "tc18_master_id": "TC18-13.7.5.1-005" + }, + { + "id": "REQ-PWM-013", + "title": "rcp_ep_pwm_out_trigger_fires() implements RCP_EP_PWM_OUT_TRIGGER_CYCLE_START", + "text": "rcp_ep_pwm_out_trigger_fires() shall return true for trigger == RCP_EP_PWM_OUT_TRIGGER_CYCLE_START iff event == RCP_EP_PWM_OUT_EVENT_CYCLE_START. CLARIFIED (2026-08-10, c-RCP-AUDIT-06, issue #256 Group C): this evaluates one of Table 45's three fixed hardware signals against a caller-selected mode -- an original single-select simplification of TC18's own always-on, non-selectable signal model; see ep_pwm.h's own file header.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.1 Table 45 (trigger signal 1, \"at the start of the cycle\"), TC18.txt L4944 -- a fixed hardware signal, not a client-configurable field", + "tc18_master_id": "TC18-13.7.5.1-005" + }, + { + "id": "REQ-PWM-014", + "title": "rcp_ep_pwm_out_trigger_fires() implements RCP_EP_PWM_OUT_TRIGGER_MID_PULSE", + "text": "rcp_ep_pwm_out_trigger_fires() shall return true for trigger == RCP_EP_PWM_OUT_TRIGGER_MID_PULSE iff event == RCP_EP_PWM_OUT_EVENT_MID_PULSE. CLARIFIED (2026-08-10, c-RCP-AUDIT-06, issue #256 Group C): this evaluates one of Table 45's three fixed hardware signals against a caller-selected mode -- an original single-select simplification of TC18's own always-on, non-selectable signal model; see ep_pwm.h's own file header.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.1 Table 45 (trigger signal 2, \"in the middle of the active pulse\"), TC18.txt L4945 -- a fixed hardware signal, not a client-configurable field", + "tc18_master_id": "TC18-13.7.5.1-005" + }, + { + "id": "REQ-PWM-015", + "title": "rcp_ep_pwm_out_trigger_fires() implements RCP_EP_PWM_OUT_TRIGGER_DONE", + "text": "rcp_ep_pwm_out_trigger_fires() shall return true for trigger == RCP_EP_PWM_OUT_TRIGGER_DONE iff event == RCP_EP_PWM_OUT_EVENT_DONE. CLARIFIED (2026-08-10, c-RCP-AUDIT-06, issue #256 Group C): this evaluates one of Table 45's three fixed hardware signals against a caller-selected mode -- an original single-select simplification of TC18's own always-on, non-selectable signal model; see ep_pwm.h's own file header.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.1 Table 45 (trigger signal 0, \"PWM request exec done (requested values applied)\"), TC18.txt L4943 -- a fixed hardware signal, not a client-configurable field", + "tc18_master_id": "TC18-13.7.5.1-005" + }, + { + "id": "REQ-PWM-016", + "title": "rcp_ep_pwm_out_functional_cfg_init() zero-initializes cfg", + "text": "rcp_ep_pwm_out_functional_cfg_init() shall set every common flag false, trigger = RCP_EP_PWM_OUT_TRIGGER_NONE, and every EP_func register (base_clk, ep_status, clk_divider, signal_flags, duty_cycle_min, duty_cycle_max, skew) to 0, regardless of cfg's prior contents.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-PWM-017", + "title": "rcp_ep_pwm_out_functional_cfg_writable() is unwritable while HW_UNCONFIGURED", + "text": "rcp_ep_pwm_out_functional_cfg_writable() shall return false for state == RCP_LIFECYCLE_HW_UNCONFIGURED regardless of writer.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.2 (\"...all access to the HW_config and EP_generic_config are locked.\"), TC18.txt L2553-2554", + "tc18_master_id": "TC18-12.3.1.2-001" + }, + { + "id": "REQ-PWM-018", + "title": "rcp_ep_pwm_out_functional_cfg_writable() requires an authorized writer while HW_CONFIGURED", + "text": "rcp_ep_pwm_out_functional_cfg_writable() shall return true for state == RCP_LIFECYCLE_HW_CONFIGURED if and only if writer.via_root_client_ep0, writer.via_owning_stream, or writer.via_discovery_stream is true, and false for an unauthorized writer. Corrected 2026-08-10 (c-RCP-AUDIT-06, issue #256 Group F): this entry previously claimed \"regardless of writer\", superseded by REQ-LIFECYCLE-030/036's authorization-gating fix (issue #198) -- the code and this module's own test (test_out_functional_cfg_writable_hw_configured_requires_authorization_or_discovery_stream, tests/test_ep_pwm.c) were already correct; only this entry's own text had gone stale.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.2 (\"Write access via EP0 to other EPs configuration is only possible for a configured 'root client' of via the discovery stream.\"), TC18.txt L2560", + "tc18_master_id": "TC18-12.3.1.2-004" + }, + { + "id": "REQ-PWM-019", + "title": "rcp_ep_pwm_out_functional_cfg_writable() requires authorization once RCP_CONFIGURED", + "text": "rcp_ep_pwm_out_functional_cfg_writable() shall return false for state == RCP_LIFECYCLE_RCP_CONFIGURED when writer indicates neither via_root_client_ep0 nor via_owning_stream, and true when either is set.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.3 (\"...only write access to the EP's functional configurations is allowed via their dedicated stream_id/byte_bus_id combinations or via root client access EP0... Write access to some parameters might be prohibited in this life-cycle state, this is marked by * in the R/W-column of the respective tables.\"), TC18.txt L2581-2582, L2601-2602", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-PWM-020", + "title": "rcp_ep_pwm_out_set_trigger() rejects an unauthorized write without mutating cfg", + "text": "rcp_ep_pwm_out_set_trigger() shall return false and leave cfg unchanged when the write is not authorized by rcp_ep_pwm_out_functional_cfg_writable().", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.3, TC18.txt L2601-2602 (W* marker convention) -- same basis as REQ-PWM-019", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-PWM-021", + "title": "rcp_ep_pwm_out_set_trigger() applies the write when authorized", + "text": "rcp_ep_pwm_out_set_trigger() shall return true and set cfg->trigger to the requested trigger when the write is authorized.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.3, TC18.txt L2601-2602 (W* marker convention) -- same basis as REQ-PWM-019", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-PWM-022", + "title": "rcp_ep_pwm_out_set_enabled() rejects an unauthorized write without mutating cfg", + "text": "rcp_ep_pwm_out_set_enabled() shall return false and leave cfg unchanged when the write is not authorized by rcp_ep_pwm_out_functional_cfg_writable().", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.3, TC18.txt L2601-2602 (W* marker convention) -- same basis as REQ-PWM-019", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-PWM-023", + "title": "rcp_ep_pwm_out_set_enabled() applies the write when authorized", + "text": "rcp_ep_pwm_out_set_enabled() shall return true and set cfg->common.ep_enable to the requested value when the write is authorized.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.3, TC18.txt L2601-2602 (W* marker convention) -- same basis as REQ-PWM-019", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-PWM-024", + "title": "rcp_ep_pwm_out_strerror() never returns NULL and is unique per code", + "text": "rcp_ep_pwm_out_strerror() shall return a non-NULL, non-empty, distinct message for each rcp_ep_pwm_out_errc_t value, including an out-of-range value.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-PWM-025", + "title": "PWM_OUT read request encode/decode round-trips", + "text": "rcp_ep_pwm_out_decode_read_request() shall, given a frame produced by rcp_ep_pwm_out_encode_read_request() with the same byte_bus_id, return RCP_EP_PWM_OUT_OK and recover the original transaction_num.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L4069-4116 (general ACF frame-validation basis for the request/response wire format)", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-PWM-026", + "title": "rcp_ep_pwm_out_decode_read_request() rejects a frame shorter than the ACF_ABB fixed header", + "text": "rcp_ep_pwm_out_decode_read_request() shall return RCP_EP_PWM_OUT_ERR_SHORT_FRAME for a frame shorter than the ACF_ABB fixed header. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of this entry's own previously-bundled text, which also asserted the BAD_MSG_TYPE, WRONG_BUS, and WRONG_OP cases now REQ-PWM-061/-062/-063's own separate ids -- four distinct error conditions, each triggered by a different malformed or misaddressed frame, the same per-outcome split REQ-PWM-002..009 already establishes.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L4069-4116", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-PWM-061", + "title": "rcp_ep_pwm_out_decode_read_request() rejects a non-ACF_ABB frame", + "text": "rcp_ep_pwm_out_decode_read_request() shall return RCP_EP_PWM_OUT_ERR_BAD_MSG_TYPE for a non-ACF_ABB frame. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-026 -- see REQ-PWM-026's own text for the split rationale.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L4069-4116", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-PWM-062", + "title": "rcp_ep_pwm_out_decode_read_request() rejects a misaddressed frame", + "text": "rcp_ep_pwm_out_decode_read_request() shall return RCP_EP_PWM_OUT_ERR_WRONG_BUS when byte_bus_id != expected_bus_id. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-026 -- see REQ-PWM-026's own text for the split rationale.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L4069-4116", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-PWM-063", + "title": "rcp_ep_pwm_out_decode_read_request() rejects a wrong-op frame", + "text": "rcp_ep_pwm_out_decode_read_request() shall return RCP_EP_PWM_OUT_ERR_WRONG_OP when op is not RCP_ACF_OP_READ. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-026 -- see REQ-PWM-026's own text for the split rationale.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L4069-4116", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-PWM-027", + "title": "PWM_OUT write request encode/decode round-trips, including evt[2:0] write semantics", + "text": "rcp_ep_pwm_out_decode_write_request() shall, given a frame produced by rcp_ep_pwm_out_encode_write_request() with the same byte_bus_id, return RCP_EP_PWM_OUT_OK and recover the original value, evt[2:0], and transaction_num.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.3 (\"The PWM_out request and response contain two values in the payload. The active time of the PWM signal as well as the period of the signal in clock ticks of the clock selected for this PWM_out endpoint.\"), TC18.txt L5031-5033; evt[2:0] semantics per §13.5 Table 33 (\"evt[2:0]\" GPIO/PWM_OUT row, values 000b-111b), TC18.txt L4093-4115", + "tc18_master_id": "TC18-13.7.5.3-001" + }, + { + "id": "REQ-PWM-028", + "title": "rcp_ep_pwm_out_decode_write_request() rejects a bad-payload-length frame", + "text": "rcp_ep_pwm_out_decode_write_request() shall return RCP_EP_PWM_OUT_ERR_BAD_PAYLOAD_LEN when the payload is not exactly RCP_EP_PWM_PAYLOAD_LEN octets; rcp_ep_pwm_out_wire_error() maps this to the numbered wire code RCP_ERROR_INVALID_PARAMETER (FIXED 2026-08-14, issue #427; dispatch-wiring gap closed 2026-08-16, issue #469 -- see REQ-PWM-008's own text for the dispatch-wiring fix). Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of this entry's own previously-bundled text, which also asserted the WRONG_OP case now REQ-PWM-064's own separate id -- two distinct error conditions, each triggered by a different malformed frame.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.3 (\"A request not having exactly four bytes is rejected and an error response with error code = INVALID_PARAMETER will be sent.\"), TC18.txt L5040-5041", + "tc18_master_id": "TC18-13.7.5.3-002" + }, + { + "id": "REQ-PWM-064", + "title": "rcp_ep_pwm_out_decode_write_request() rejects a wrong-op frame", + "text": "rcp_ep_pwm_out_decode_write_request() shall return RCP_EP_PWM_OUT_ERR_WRONG_OP when op is not RCP_ACF_OP_WRITE. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-028 -- see REQ-PWM-028's own text for the split rationale.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.3 (\"A request not having exactly four bytes is rejected and an error response with error code = INVALID_PARAMETER will be sent.\"), TC18.txt L5040-5041", + "tc18_master_id": "TC18-13.7.5.3-002" + }, + { + "id": "REQ-PWM-029", + "title": "PWM_OUT response encode/decode round-trips when untimed", + "text": "rcp_ep_pwm_out_decode_response() shall, given a frame produced by rcp_ep_pwm_out_encode_response() with timed = false and the same byte_bus_id, return RCP_EP_PWM_OUT_OK, recover the original value and transaction_num, and report *out_timed = false with *out_timestamp = 0.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.3 (\"The PWM_out request and response contain two values in the payload.\"), TC18.txt L5031-5033", + "tc18_master_id": "TC18-13.7.5.3-001" + }, + { + "id": "REQ-PWM-030", + "title": "PWM_OUT response encode/decode round-trips when timed", + "text": "rcp_ep_pwm_out_decode_response() shall, given a frame produced by rcp_ep_pwm_out_encode_response() with timed = true, the same byte_bus_id, and a timestamp, return RCP_EP_PWM_OUT_OK, recover the original value and transaction_num, and report *out_timed = true with *out_timestamp equal to the original timestamp.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.3 (\"The PWM_out request and response contain two values in the payload.\"), TC18.txt L5031-5033", + "tc18_master_id": "TC18-13.7.5.3-001" + }, + { + "id": "REQ-PWM-031", + "title": "rcp_ep_pwm_out_decode_response() rejects a frame too short for its ACF fixed header", + "text": "rcp_ep_pwm_out_decode_response() shall return RCP_EP_PWM_OUT_ERR_SHORT_FRAME for a frame too short for its applicable ACF fixed header. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of this entry's own previously-bundled text, which also asserted the WRONG_BUS case now REQ-PWM-065's own separate id.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L4069-4116 (general ACF frame-validation basis)", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-PWM-065", + "title": "rcp_ep_pwm_out_decode_response() rejects a misaddressed frame", + "text": "rcp_ep_pwm_out_decode_response() shall return RCP_EP_PWM_OUT_ERR_WRONG_BUS when byte_bus_id != expected_bus_id. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-031 -- see REQ-PWM-031's own text for the split rationale. No dedicated test previously existed for this specific clause (the PWM_IN sibling, REQ-PWM-046, already had one via test_in_response_decode_rejects_wrong_bus; PWM_OUT's own decode_response never had the equivalent) -- exactly the silent-gap risk this audit exists to close; added test_out_response_decode_rejects_wrong_bus.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L4069-4116 (general ACF frame-validation basis)", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-PWM-032", + "title": "rcp_ep_pwm_in_trigger_fires() never fires for RCP_EP_PWM_IN_TRIGGER_NONE", + "text": "rcp_ep_pwm_in_trigger_fires() shall return false for trigger == RCP_EP_PWM_IN_TRIGGER_NONE regardless of the level transition. CLARIFIED (2026-08-10, c-RCP-AUDIT-06, issue #256 Group C): NONE is this module's own original addition -- TC18 Table 47 documents two fixed, always-on trigger signals with no off/none state and no client-selectable register at all (PWM_IN's functional config has no trigger-select field). See ep_pwm.h's own file header.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.6.1 Table 47 (\"The PWM_IN endpoint [optionally] generates two trigger events\"), TC18.txt L5081-5087 -- names two fixed hardware signals, not a client-configurable field.", + "tc18_master_id": "TC18-13.7.6.1-002" + }, + { + "id": "REQ-PWM-033", + "title": "rcp_ep_pwm_in_trigger_fires() implements RCP_EP_PWM_IN_TRIGGER_RISING", + "text": "rcp_ep_pwm_in_trigger_fires() shall return true for trigger == RCP_EP_PWM_IN_TRIGGER_RISING iff prev_level is false and new_level is true. CLARIFIED (2026-08-10, c-RCP-AUDIT-06, issue #256 Group C): this evaluates one of Table 47's two fixed hardware signals against a caller-selected mode -- an original single-select simplification; see ep_pwm.h's own file header.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.6.1 Table 47 (trigger signal 0, \"rising edge of PWM_IN signal\"), TC18.txt L5085 -- a fixed hardware signal, not a client-configurable field.", + "tc18_master_id": "TC18-13.7.6.1-002" + }, + { + "id": "REQ-PWM-034", + "title": "rcp_ep_pwm_in_trigger_fires() implements RCP_EP_PWM_IN_TRIGGER_FALLING", + "text": "rcp_ep_pwm_in_trigger_fires() shall return true for trigger == RCP_EP_PWM_IN_TRIGGER_FALLING iff prev_level is true and new_level is false. CLARIFIED (2026-08-10, c-RCP-AUDIT-06, issue #256 Group C): this evaluates one of Table 47's two fixed hardware signals against a caller-selected mode -- an original single-select simplification; see ep_pwm.h's own file header.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.6.1 Table 47 (trigger signal 1, \"falling edge of PWM_IN signal\"), TC18.txt L5086 -- a fixed hardware signal, not a client-configurable field.", + "tc18_master_id": "TC18-13.7.6.1-002" + }, + { + "id": "REQ-PWM-035", + "title": "rcp_ep_pwm_in_functional_cfg_init() zero-initializes cfg", + "text": "rcp_ep_pwm_in_functional_cfg_init() shall set every common flag false and trigger = RCP_EP_PWM_IN_TRIGGER_NONE, regardless of cfg's prior contents.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-PWM-036", + "title": "rcp_ep_pwm_in_functional_cfg_writable() is unwritable while HW_UNCONFIGURED", + "text": "rcp_ep_pwm_in_functional_cfg_writable() shall return false for state == RCP_LIFECYCLE_HW_UNCONFIGURED regardless of writer.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.2 (\"...all access to the HW_config and EP_generic_config are locked.\"), TC18.txt L2553-2554", + "tc18_master_id": "TC18-12.3.1.2-001" + }, + { + "id": "REQ-PWM-037", + "title": "rcp_ep_pwm_in_functional_cfg_writable() requires an authorized writer while HW_CONFIGURED", + "text": "rcp_ep_pwm_in_functional_cfg_writable() shall return true for state == RCP_LIFECYCLE_HW_CONFIGURED if and only if writer.via_root_client_ep0, writer.via_owning_stream, or writer.via_discovery_stream is true, and false for an unauthorized writer. Corrected 2026-08-10 (c-RCP-AUDIT-06, issue #256 Group F): this entry previously claimed \"regardless of writer\", the same staleness as REQ-PWM-018's PWM_OUT counterpart -- the code and this module's own test (test_in_functional_cfg_writable_hw_configured_requires_authorization_or_discovery_stream, tests/test_ep_pwm.c) were already correct; only this entry's own text had gone stale.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.2 (\"Write access via EP0 to other EPs configuration is only possible for a configured 'root client' of via the discovery stream.\"), TC18.txt L2560", + "tc18_master_id": "TC18-12.3.1.2-004" + }, + { + "id": "REQ-PWM-038", + "title": "rcp_ep_pwm_in_functional_cfg_writable() requires authorization once RCP_CONFIGURED", + "text": "rcp_ep_pwm_in_functional_cfg_writable() shall return false for state == RCP_LIFECYCLE_RCP_CONFIGURED when writer indicates neither via_root_client_ep0 nor via_owning_stream, and true when either is set.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.3, TC18.txt L2581-2582, L2601-2602 (W* marker convention) -- same basis as REQ-PWM-019", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-PWM-039", + "title": "rcp_ep_pwm_in_set_trigger() rejects an unauthorized write without mutating cfg", + "text": "rcp_ep_pwm_in_set_trigger() shall return false and leave cfg unchanged when the write is not authorized by rcp_ep_pwm_in_functional_cfg_writable().", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.3, TC18.txt L2601-2602 (W* marker convention) -- same basis as REQ-PWM-019", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-PWM-040", + "title": "rcp_ep_pwm_in_set_trigger() applies the write when authorized", + "text": "rcp_ep_pwm_in_set_trigger() shall return true and set cfg->trigger to the requested trigger when the write is authorized.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.3, TC18.txt L2601-2602 (W* marker convention) -- same basis as REQ-PWM-019", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-PWM-041", + "title": "rcp_ep_pwm_in_strerror() never returns NULL and is unique per code", + "text": "rcp_ep_pwm_in_strerror() shall return a non-NULL, non-empty, distinct message for each rcp_ep_pwm_in_errc_t value.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-PWM-042", + "title": "PWM_IN read request encode/decode round-trips", + "text": "rcp_ep_pwm_in_decode_read_request() shall, given a frame produced by rcp_ep_pwm_in_encode_read_request() with the same byte_bus_id, return RCP_EP_PWM_IN_OK and recover the original transaction_num.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.6.3 (\"The PWM_IN request and response contain two 16 bit values in the payload... The interpretation of the evt-bits is described in the section 'The usage of evt bits in requests'.\"), TC18.txt L5169-5180", + "tc18_master_id": "TC18-13.7.6.3-001" + }, + { + "id": "REQ-PWM-043", + "title": "rcp_ep_pwm_in_decode_read_request() rejects a frame shorter than the ACF_ABB fixed header", + "text": "rcp_ep_pwm_in_decode_read_request() shall return RCP_EP_PWM_IN_ERR_SHORT_FRAME for a frame shorter than the ACF_ABB fixed header. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of this entry's own previously-bundled text, which also asserted the WRONG_BUS case now REQ-PWM-066's own separate id.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L4069-4116 (general ACF frame-validation basis)", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-PWM-066", + "title": "rcp_ep_pwm_in_decode_read_request() rejects a misaddressed frame", + "text": "rcp_ep_pwm_in_decode_read_request() shall return RCP_EP_PWM_IN_ERR_WRONG_BUS when byte_bus_id != expected_bus_id. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-043 -- see REQ-PWM-043's own text for the split rationale.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L4069-4116 (general ACF frame-validation basis)", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-PWM-044", + "title": "PWM_IN response encode/decode round-trips when untimed", + "text": "rcp_ep_pwm_in_decode_response() shall, given a frame produced by rcp_ep_pwm_in_encode_response() with timed = false and the same byte_bus_id, return RCP_EP_PWM_IN_OK, recover the original value and transaction_num, and report *out_timed = false with *out_timestamp = 0.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.6.3 (\"Responses include the measured active time of the PWM signal as well as the period of the signal in clock ticks of the clock selected for this PWM_IN endpoint.\"), TC18.txt L5170-5172", + "tc18_master_id": "TC18-13.7.6.3-001" + }, + { + "id": "REQ-PWM-045", + "title": "PWM_IN response encode/decode round-trips when timed", + "text": "rcp_ep_pwm_in_decode_response() shall, given a frame produced by rcp_ep_pwm_in_encode_response() with timed = true, the same byte_bus_id, and a timestamp, return RCP_EP_PWM_IN_OK, recover the original value and transaction_num, and report *out_timed = true with *out_timestamp equal to the original timestamp.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.6.3 (\"Responses include the measured active time of the PWM signal as well as the period of the signal in clock ticks of the clock selected for this PWM_IN endpoint.\"), TC18.txt L5170-5172", + "tc18_master_id": "TC18-13.7.6.3-001" + }, + { + "id": "REQ-PWM-046", + "title": "rcp_ep_pwm_in_decode_response() rejects a misaddressed frame", + "text": "rcp_ep_pwm_in_decode_response() shall return RCP_EP_PWM_IN_ERR_WRONG_BUS when byte_bus_id != expected_bus_id.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L4069-4116 (general ACF frame-validation basis)", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-PWM-047", + "title": "PWM_IN response encode/decode round-trips RCP_EP_PWM_IN_NO_SIGNAL verbatim", + "text": "rcp_ep_pwm_in_decode_response() shall, given a frame produced by rcp_ep_pwm_in_encode_response() with either or both of value's fields equal to RCP_EP_PWM_IN_NO_SIGNAL, recover that sentinel unchanged, treating it as an ordinary uint16_t value with no special decode-time handling. RESOLVED (issue #184, c-RCP-AUDIT-05), left honestly uncited rather than force-cited: TC18 defines PWM_IN_NO_SIGNAL solely as a numbered wire error code (§12.9.6 Table 30, value 9, carried via the response err field -- not \"Table 27\", a stale pre-RC5 number; see #339/#342's own citation-drift correction) for the one no-signal case it documents in prose (§13.7.6.1: the external PWM source stopping, reported via an error response \"if enabled within EP_config (EP_RESP_ON_ERR)\"; rcp_ep_pwm_in_max_period_outcome()'s STOP_AND_ERROR outcome, REQ-PWM-058, already routes exactly that case to the real Table 30 code, not this sentinel). TC18 defines no payload-sentinel convention anywhere, and is silent on what a Read Response should carry when EP_RESP_ON_ERR is disabled or before any valid capture exists in continuous mode. RCP_EP_PWM_IN_NO_SIGNAL (0xFFFF) as an in-payload value is this codebase's own invention for exactly those TC18-silent cases -- a defensible implementation choice, not a citation gap.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-PWM-048", + "title": "rcp_ep_pwm_in_compound_wait_mode_valid() accepts exactly 4..7", + "text": "rcp_ep_pwm_in_compound_wait_mode_valid() shall return true for every value v with 4 <= v <= 7, and false for every other value.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5.1 (\"evt[2:0] = 100b ... wait condition is met when the first two bytes... larger or equal...\" through \"evt[2:0] = 111b\"), TC18.txt L4152-4163", + "tc18_master_id": "TC18-13.5.1-002" + }, + { + "id": "REQ-PWM-049", + "title": "rcp_ep_pwm_in_compound_wait_compare() implements RCP_EP_PWM_IN_CMP_PERIOD_GE", + "text": "rcp_ep_pwm_in_compound_wait_compare() shall, for mode == RCP_EP_PWM_IN_CMP_PERIOD_GE, return true iff captured.period is not RCP_EP_PWM_IN_NO_SIGNAL and captured.period <= threshold (threshold is TC18's byte_msg_payload, captured.period is the current interface status -- \"GE\" describes payload >= status, not status >= threshold). Corrected 2026-08-10 (c-RCP-AUDIT-06, issue #256 Group B): this entry, and the code it described, previously had the comparison reversed (captured.period >= threshold), contradicted by both the primary source and this codebase's own reference implementation of the identical §13.5.1 rule, rcp_acf_compound_wait_match() (src/acf.c).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5.1 (\"evt[2:0] = 100b 0xB - wait condition is met when the first two bytes of the first quadlet of 'byte_msg_payload' is larger or equal to the first two bytes of the first quadlet of the 'current interface status' (example: this can be used to check the period of PWM_in)\"), TC18.txt L4152-4154", + "tc18_master_id": "TC18-13.5.1-002" + }, + { + "id": "REQ-PWM-050", + "title": "rcp_ep_pwm_in_compound_wait_compare() implements RCP_EP_PWM_IN_CMP_PERIOD_LE", + "text": "rcp_ep_pwm_in_compound_wait_compare() shall, for mode == RCP_EP_PWM_IN_CMP_PERIOD_LE, return true iff captured.period is not RCP_EP_PWM_IN_NO_SIGNAL and captured.period >= threshold (threshold is TC18's byte_msg_payload, captured.period is the current interface status -- \"LE\" describes payload <= status, not status <= threshold). Corrected 2026-08-10 (c-RCP-AUDIT-06, issue #256 Group B): this entry, and the code it described, previously had the comparison reversed (captured.period <= threshold), the mirror of REQ-PWM-049's own correction.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5.1 (\"evt[2:0] = 101b - wait condition is met when the first two bytes of the first quadlet of 'byte_msg_payload' is smaller or to equal the first two bytes of the first quadlet of the 'current interface status' (example: this can be used to check the period of PWM_in)\"), TC18.txt L4155-4157", + "tc18_master_id": "TC18-13.5.1-002" + }, + { + "id": "REQ-PWM-051", + "title": "rcp_ep_pwm_in_compound_wait_compare() implements RCP_EP_PWM_IN_CMP_DUTY_GE", + "text": "rcp_ep_pwm_in_compound_wait_compare() shall, for mode == RCP_EP_PWM_IN_CMP_DUTY_GE, return true iff captured.active_duration is not RCP_EP_PWM_IN_NO_SIGNAL and captured.active_duration <= threshold (threshold is TC18's byte_msg_payload, captured.active_duration is the current interface status -- \"GE\" describes payload >= status, not status >= threshold). Corrected 2026-08-10 (c-RCP-AUDIT-06, issue #256 Group B): this entry, and the code it described, previously had the comparison reversed (captured.active_duration >= threshold), the same class of error as REQ-PWM-049.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5.1 (\"evt[2:0] = 110b - wait condition is met when the last two bytes of the first quadlet of 'byte_msg_payload' is larger or equal to the last two bytes of the first quadlet of the 'current interface status' (example: this can be used to check the duty_cycle of PWM_in)\"), TC18.txt L4158-4160", + "tc18_master_id": "TC18-13.5.1-002" + }, + { + "id": "REQ-PWM-052", + "title": "rcp_ep_pwm_in_compound_wait_compare() implements RCP_EP_PWM_IN_CMP_DUTY_LE", + "text": "rcp_ep_pwm_in_compound_wait_compare() shall, for mode == RCP_EP_PWM_IN_CMP_DUTY_LE, return true iff captured.active_duration is not RCP_EP_PWM_IN_NO_SIGNAL and captured.active_duration >= threshold (threshold is TC18's byte_msg_payload, captured.active_duration is the current interface status -- \"LE\" describes payload <= status, not status <= threshold). Corrected 2026-08-10 (c-RCP-AUDIT-06, issue #256 Group B): this entry, and the code it described, previously had the comparison reversed (captured.active_duration <= threshold), the mirror of REQ-PWM-051's own correction.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5.1 (\"evt[2:0] = 111b - wait condition is met when the last two bytes of the first quadlet of 'byte_msg_payload' is smaller or to equal... (example: this can be used to check the duty_cycle of PWM_in)\"), TC18.txt L4161-4163", + "tc18_master_id": "TC18-13.5.1-002" + }, + { + "id": "REQ-PWM-053", + "title": "rcp_ep_pwm_in_compound_wait_compare() returns false for an invalid mode", + "text": "rcp_ep_pwm_in_compound_wait_compare() shall return false, never treating it as a match, for any mode value outside RCP_EP_PWM_IN_CMP_PERIOD_GE..RCP_EP_PWM_IN_CMP_DUTY_LE (4..7).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5.1, TC18.txt L4152-4163 -- only evt[2:0]=100b..111b (4..7) are defined compound-wait comparison modes for PWM_in in this table", + "tc18_master_id": "TC18-13.5.1-002" + }, + { + "id": "REQ-PWM-054", + "title": "rcp_ep_pwm_in_compound_wait_compare() never matches a RCP_EP_PWM_IN_NO_SIGNAL sub-field", + "text": "rcp_ep_pwm_in_compound_wait_compare() shall return false for every defined mode whenever the sub-field that mode compares (captured.period for PERIOD_GE/PERIOD_LE, captured.active_duration for DUTY_GE/DUTY_LE) equals RCP_EP_PWM_IN_NO_SIGNAL, regardless of threshold. RESOLVED (issue #184, c-RCP-AUDIT-05), left honestly uncited rather than force-cited: the RCP_EP_PWM_IN_NO_SIGNAL payload sentinel this rule guards against has no TC18 basis of its own -- see REQ-PWM-047's own resolution note for the full analysis (TC18 defines PWM_IN_NO_SIGNAL only as a numbered §12.9.6 Table 30 error code, never a payload value).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-PWM-055", + "title": "PWM_OUT trigger events are derived from the skew-delayed signal, not the undelayed source edge", + "text": "rcp_ep_pwm_out_trigger_events_at_tick() shall derive CYCLE_START/MID_PULSE trigger timing relative to the pwmo_skew-delayed edge, not the undelayed source edge that raw_tick is itself measured from (TC18 §13.7.5.1's own break-before-make provision: \"for trigger signal generation the delayed signal is used\"). Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of this entry's own previously-bundled text, which also asserted Table 45's separate \"MID_PULSE fires even at 0% duty cycle\" carve-out, now REQ-PWM-067's own separate id -- two independently testable rules of the same function.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.1, TC18.txt L4924-4935 and Table 45 L4939-4947", + "tc18_master_id": "TC18-13.7.5.1-005" + }, + { + "id": "REQ-PWM-067", + "title": "PWM_OUT MID_PULSE fires at the delayed cycle start even when active_duration is 0", + "text": "rcp_ep_pwm_out_trigger_events_at_tick() shall still fire MID_PULSE at the delayed cycle start when active_duration == 0, rather than suppressing it (TC18 Table 45's own event-2 row: \"in the middle of the active pulse (even in case duty cycle is 0%)\"). Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-055 -- see REQ-PWM-055's own text for the split rationale.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.1, TC18.txt L4924-4935 and Table 45 L4939-4947", + "tc18_master_id": "TC18-13.7.5.1-005" + }, + { + "id": "REQ-PWM-056", + "title": "PWM_OUT duty-cycle limits cap the requested active time", + "text": "IMPLEMENTED (2026-08-12, issue #201 Phase 5e): rcp_ep_pwm_out_apply_write() now takes duty_cycle_min/duty_cycle_max parameters (the endpoint's own pwmo_duty_cycle_min/pwmo_duty_cycle_max register values) and clamps the resulting active_duration into [duty_cycle_min, duty_cycle_max] after evt's own write semantics have already been applied, per TC18 Table 46's own wording (\"requests with lower values will be capped to this limit\" / \"requests with higher values will be capped to this limit\") -- capped, not rejected and not applied verbatim. period is unaffected, since Table 46 names only \"PWM active\" (the active-phase duration). Real signature change to a function with real callers: updated every call site (12 in tests/test_ep_pwm.c with no-op [0, 0xFFFF] limits that don't affect their own existing assertions, 5 in tests/test_tc18_gaps_ep.c). Split the pre-existing combined REQ-PWM-055/REQ-PWM-056 gap-pinning test into two -- REQ-PWM-055 (trigger-signal generation from the skew-delayed output, mid-pulse firing at 0% duty) remains a genuine, still-open deviation pin, since it needs a real timing/signal-generation model this protocol-codec library does not have. Mutation-tested 3 ways: bypassing capping entirely (caught), the min-boundary comparison reversed to the wrong direction (caught heavily), and the min-boundary's own < vs <= operator (a provably equivalent mutant -- assigning duty_cycle_min to a value already equal to duty_cycle_min is a no-op, so no test of the output can discriminate the two operators there).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.5.2 Table 46, TC18.txt L4967-5012", + "tc18_master_id": "TC18-13.7.5.2-001" + }, + { + "id": "REQ-PWM-057", + "title": "rcp_ep_pwm_out_generation_state() classifies period == 0 as stopped", + "text": "rcp_ep_pwm_out_generation_state() shall return RCP_EP_PWM_OUT_GEN_STOPPED whenever value.period == 0, regardless of active_duration. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of this entry's own previously-bundled text, which also asserted the active_duration == 0 (output-disabled) and both-nonzero (running) outcomes, now REQ-PWM-068/-069's own separate ids -- three distinct classifier outcomes of one {period, active_duration} pair, the same per-outcome split REQ-PWM-002..009 already establishes. The other 2 of TC18 13.7.5.3's own 4 PWM_OUT request rules (phase-shift interpretation, output-pin readback) remain the genuinely out-of-scope deviation this entry always pinned: a trigger-configuration request's first two payload octets carrying a PHASE SHIFT depends on the conditional-request layer's own request-kind classification this endpoint's decode path has no connection to today (TC18 spec-defects report items 11-12 document a live, unresolved request_type collision in that harmonization effort), and output-pin readback needs real physical IO this protocol-codec library has never modelled for any endpoint type.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18-gap", + "status": "partial", + "tc18": "§13.7.5.3, TC18.txt L5030-5049" + }, + { + "id": "REQ-PWM-068", + "title": "rcp_ep_pwm_out_generation_state() classifies active_duration == 0 (period != 0) as output-disabled", + "text": "rcp_ep_pwm_out_generation_state() shall return RCP_EP_PWM_OUT_GEN_OUTPUT_DISABLED when value.active_duration == 0 and value.period != 0 -- the endpoint keeps running with the output disabled while trigger signals still fire. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-057 -- see REQ-PWM-057's own text for the split rationale.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18-gap", + "status": "partial", + "tc18": "§13.7.5.3, TC18.txt L5030-5049" + }, + { + "id": "REQ-PWM-069", + "title": "rcp_ep_pwm_out_generation_state() classifies a nonzero period and active_duration as running", + "text": "rcp_ep_pwm_out_generation_state() shall return RCP_EP_PWM_OUT_GEN_RUNNING when both value.period and value.active_duration are nonzero. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-057 -- see REQ-PWM-057's own text for the split rationale.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18-gap", + "status": "partial", + "tc18": "§13.7.5.3, TC18.txt L5030-5049" + }, + { + "id": "REQ-PWM-058", + "title": "PWM_IN functional-config register block (Table 48)", + "text": "IMPLEMENTED (FIXED 2026-08-11, c-RCP-AUDIT-06, issue #256 Group I): c-RCP's rcp_ep_pwm_in_functional_cfg_t models every TC18 Table 48 PWM_IN register -- pwmi_polarity, pwmi_err_on_max_period, pwmi_continuous_mode (packed into a new flags octet at 0x0009, RCP_EP_PWM_IN_FLAG_* masks), pwmi_max_period (0x000A-0x000B), pwmi_base_clk (0x0004-0x0005, read-only), pwmi_clk_divider (0x0008), and pwmi_ep_status (0x0006-0x0007) -- reachable via the same generic evt[2:0]=111b TC18 §12.7.1 register-block mechanism every other endpoint type now has: rcp_ep_pwm_in_render_registers()/_apply_reconfig()/_reconfig_strerror()/_encode_reconfig_request(). `trigger` remains a non-wire, module-own field; the measurement-timeout sentinel RCP_EP_PWM_IN_NO_SIGNAL is unrelated to the register block. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533): this entry's own text previously also narrated (a) rcp_ep_pwm_in_apply_reconfig()'s two addressed-write error conditions, now REQ-PWM-070/-071's own separate ids (mirroring REQ-PWM-010/-011's identical split for PWM_OUT), and (b) the MAX_PERIOD timeout classifier rcp_ep_pwm_in_max_period_outcome()'s four Table 48 outcomes, now REQ-PWM-072..075's own separate ids -- different functions with their own independently-testable branches, not this entry's register-block claim, which this entry now covers alone. KNOWN RESIDUAL BUNDLE, not fixed by this split: this entry's own tag still also sits above render_registers()/reconfig_strerror()/encode_reconfig_request(), none of whose own distinct behaviour (register serialization, error-message lookup, frame encoding) this entry's text actually describes -- the same class of helper-hitchhikes-on-an-unrelated-id gap #519 documented for saturating_add_u16/_sub_u16, and which PWM_OUT's own REQ-PWM-010 exhibits identically for its render_registers()/encode_reconfig_request(), and REQ-PWM-011 for its own reconfig_strerror() -- deferred to a follow-up batch rather than fixed here, mirroring #519's own documented-but-deferred treatment of the func-coverage gap it found.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.6.2 Table 48, TC18.txt L5104-5149", + "tc18_master_id": "TC18-13.7.6.2-001" + }, + { + "id": "REQ-PWM-070", + "title": "rcp_ep_pwm_in_apply_reconfig() ignores a configuration write with no address+data", + "text": "rcp_ep_pwm_in_apply_reconfig() shall return RCP_EP_PWM_IN_RECONFIG_ERR_SHORT when the payload does not carry a 2-octet address plus at least one data octet, leaving cfg entirely unchanged. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-058, whose own text previously bundled this addressed-write error condition (among others) under one id -- see REQ-PWM-058's own text for the split rationale, and REQ-PWM-011's own identical PWM_OUT-side split for the precedent this mirrors.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.6.2 Table 48, TC18.txt L5104-5149", + "tc18_master_id": "TC18-13.7.6.2-001" + }, + { + "id": "REQ-PWM-071", + "title": "rcp_ep_pwm_in_apply_reconfig() ignores a configuration write that extends past EP_LEN", + "text": "rcp_ep_pwm_in_apply_reconfig() shall return RCP_EP_PWM_IN_RECONFIG_ERR_OUT_OF_RANGE when start_address plus the data length exceeds RCP_EP_PWM_IN_EP_FUNC_LEN, leaving cfg entirely unchanged. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-058 -- see REQ-PWM-058's own text for the split rationale, and REQ-PWM-060's own identical PWM_OUT-side split for the precedent this mirrors.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.6.2 Table 48, TC18.txt L5104-5149", + "tc18_master_id": "TC18-13.7.6.2-001" + }, + { + "id": "REQ-PWM-072", + "title": "rcp_ep_pwm_in_max_period_outcome() reports OK when the measured period is within bound", + "text": "rcp_ep_pwm_in_max_period_outcome() shall return RCP_EP_PWM_IN_MAX_PERIOD_OK whenever measured_period <= max_period, regardless of err_on_max_period or resp_on_err_enabled. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-058, whose own text previously narrated this classifier's Table 48 outcomes collectively -- see REQ-PWM-058's own text for the split rationale.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.6.2 Table 48, TC18.txt L5104-5149", + "tc18_master_id": "TC18-13.7.6.2-001" + }, + { + "id": "REQ-PWM-073", + "title": "rcp_ep_pwm_in_max_period_outcome() invalidates the measurement and never errors when pwmi_err_on_max_period is clear", + "text": "rcp_ep_pwm_in_max_period_outcome() shall return RCP_EP_PWM_IN_MAX_PERIOD_INVALIDATE whenever measured_period > max_period and err_on_max_period is false, regardless of resp_on_err_enabled (Table 48's own 0b row: \"invalidate measurement and wait for new active phase of signal\"). Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-058 -- see REQ-PWM-058's own text for the split rationale.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.6.2 Table 48, TC18.txt L5104-5149", + "tc18_master_id": "TC18-13.7.6.2-001" + }, + { + "id": "REQ-PWM-074", + "title": "rcp_ep_pwm_in_max_period_outcome() stops the measurement without erroring when EP_RESP_ON_ERR is disabled", + "text": "rcp_ep_pwm_in_max_period_outcome() shall return RCP_EP_PWM_IN_MAX_PERIOD_STOP whenever measured_period > max_period, err_on_max_period is true, and resp_on_err_enabled is false (Table 48's own 1b row: \"stop measurement and signal error if error response is enabled in EP_config\" -- the stop always happens, the error is conditional). Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-058 -- see REQ-PWM-058's own text for the split rationale.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.6.2 Table 48, TC18.txt L5104-5149", + "tc18_master_id": "TC18-13.7.6.2-001" + }, + { + "id": "REQ-PWM-075", + "title": "rcp_ep_pwm_in_max_period_outcome() stops the measurement and signals an error when EP_RESP_ON_ERR is enabled", + "text": "rcp_ep_pwm_in_max_period_outcome() shall return RCP_EP_PWM_IN_MAX_PERIOD_STOP_AND_ERROR whenever measured_period > max_period, err_on_max_period is true, and resp_on_err_enabled is true. Split 2026-08-18 (c-RCP-18-tracker, REQ-PWM-* atomicity audit, issue #533) out of REQ-PWM-058 -- see REQ-PWM-058's own text for the split rationale.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.6.2 Table 48, TC18.txt L5104-5149", + "tc18_master_id": "TC18-13.7.6.2-001" + }, + { + "id": "REQ-PWM-059", + "title": "PWM_IN read-request decode validates evt[2:0]", + "text": "IMPLEMENTED (FIXED 2026-08-11, c-RCP-AUDIT-06, issue #256 Group I): rcp_ep_pwm_in_decode_read_request() shall reject a frame whose evt[2:0] is not one of the plain-request values rcp_acf_evt_row2_is_plain() accepts, returning RCP_EP_PWM_IN_ERR_BAD_EVT -- matching the check every other endpoint type in this Table 33 grouping (ADC/I2C/LIN/CAN/UART/ISELED/MDIO) already performs. Before this fix, this endpoint type never checked evt[2:0] at all: a real evt=111b configuration-write request from a conforming peer would have been silently misinterpreted as an ordinary read request rather than being rejected or routed to rcp_ep_pwm_in_apply_reconfig() -- a live conformance bug, distinct from (and worse than) every prior Group I register-block finding, which found only an unreachable path, never a misinterpreted one.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L4069-4116; §13.7.6.2 Table 48, TC18.txt L5104-5149", + "tc18_master_id": "TC18-13.5-001" } ] } diff --git a/tests/test_pwm.cpp b/tests/test_pwm.cpp index af92d1c..0972047 100644 --- a/tests/test_pwm.cpp +++ b/tests/test_pwm.cpp @@ -530,6 +530,16 @@ TEST_CASE("PWM_OUT decode_read_request rejects a short frame", "[pwm][REQ-PWM-02 REQUIRE(decode_read_request(buf.data(), buf.size(), 0, txn) == make_error_code(PwmErrc::short_frame)); } +TEST_CASE("PWM_OUT decode_read_request rejects a non-ACF_ABB frame", "[pwm][REQ-PWM-061]") { + rcp::acf::AcfMessageInfo hdr; + hdr.byte_bus_id = 7; + hdr.op = false; + const auto frame = rcp::acf::encode_acf_gbb(hdr, 0, {}); + + uint8_t txn = 0; + REQUIRE(decode_read_request(frame.data(), frame.size(), 7, txn) == make_error_code(PwmErrc::bad_msg_type)); +} + TEST_CASE("PWM_OUT decode_read_request rejects a misaddressed frame", "[pwm][REQ-PWM-062]") { auto frame = encode_read_request(7, 1); uint8_t txn = 0; @@ -639,6 +649,38 @@ TEST_CASE("PwmErrc reports a non-empty message in its own category", "[pwm][REQ- REQUIRE_FALSE(ec.message().empty()); } +// c-RCP models PWM_OUT/PWM_IN error strings via two distinct functions +// (rcp_ep_pwm_out_strerror()/rcp_ep_pwm_in_strerror(), REQ-PWM-024/REQ-PWM-041 +// respectively); this port shares one PwmErrc/pwm_category() across both +// endpoint types (see the file header), so one exhaustive test discharges +// both requirements' "non-NULL, non-empty, distinct message per code, +// including an out-of-range value" contract at once. +TEST_CASE("PwmErrc::message is non-empty and distinct for every defined code, and for an out-of-range code", + "[pwm][REQ-PWM-024][REQ-PWM-041]") { + const PwmErrc codes[] = { + PwmErrc::no_signal, PwmErrc::config_write_not_supported, PwmErrc::short_frame, + PwmErrc::bad_msg_type, PwmErrc::wrong_bus, PwmErrc::wrong_op, + PwmErrc::bad_payload_len, PwmErrc::reserved_evt, PwmErrc::bad_evt, + PwmErrc::reconfig_short, PwmErrc::reconfig_out_of_range, + }; + std::vector messages; + for (auto code : codes) { + auto msg = make_error_code(code).message(); + REQUIRE_FALSE(msg.empty()); + messages.push_back(msg); + } + for (size_t i = 0; i < messages.size(); ++i) { + for (size_t j = i + 1; j < messages.size(); ++j) { + REQUIRE(messages[i] != messages[j]); + } + } + + // Out-of-range value: the category's own message() still returns a + // non-empty, non-crashing string via its default case. + auto out_of_range = pwm_category().message(9999); + REQUIRE_FALSE(out_of_range.empty()); +} + TEST_CASE("wire_error maps bad_payload_len to InvalidParameter and no_signal to PwmInNoSignal", "[pwm][REQ-PWM-028]") { REQUIRE(wire_error(PwmErrc::bad_payload_len) == rcp::acf::WireErrorCode::InvalidParameter);