diff --git a/.fusa-reqs-pending.json b/.fusa-reqs-pending.json index d3a99e2..80e7463 100644 --- a/.fusa-reqs-pending.json +++ b/.fusa-reqs-pending.json @@ -513,6 +513,271 @@ "tc18": "§13.7.12.2 Table 58, TC18.txt L5950-5952 (\"iseled_use_rcv_clk ... Use clock provided by ISELED 1st device instead of FreqSync pattern\"); §13.7.12.2 (\"For receiving ISELED frames on the ISP_P Pin of the interface either a clock synchronization via the Freq_Sync pattern can be done or data sampling based on the clock provided on the ISP_N pin. If the Freq_Sync pattern is used it is not necessary to connect the ISP_N of the EP to a physical Pin.\"), TC18.txt L5964-5966", "tc18_master_id": "TC18-13.7.12.2-004", "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 7, ISELED (iseled.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/iseled.hpp / tests/test_iseled.cpp. The blocker is that cpp-RCP's pre-existing REQ-ISELED-* 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-ISELED-007 (\"IseledEndpoint::handle_request reports config-write (evt[2:0]==111b) as not yet supported\"). Genuinely implemented+tested: rcp::iseled::requires_isp_n(use_rcv_clk) (iseled.hpp) is a real constexpr function returning use_rcv_clk directly -- tests/test_iseled.cpp's \"requires_isp_n is true iff use_rcv_clk is true\" TEST_CASE exercises both polarities." + }, + { + "id": "REQ-I2C-001", + "title": "rcp_ep_i2c_mode_valid() accepts exactly the five defined presets", + "text": "rcp_ep_i2c_mode_valid() shall return true for v in 0..4 (RCP_EP_I2C_MODE_STANDARD..RCP_EP_I2C_MODE_ULTRA_FAST) and false for any other value.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.7.7.2 Table 49 (i2c functional configuration; RC5 renumbering of RC1's Table 46), TC18.txt L5206-5235 (i2c_mode, 0x0007, values 0-4 with a duplicated \"3:\" high-speed labeling); REQ-I2C-019 (issue #256 Group I) closed the Ultra-fast (value 4) gap, and this module's conservative lower-numbered reading of the ambiguous \"High-speed\" row still resolves to 3, so the valid range is now 0..4, not the pre-fix 0..3", + "tc18_master_id": "TC18-13.7.7.2-001", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 8, I2C (i2c.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/i2c.hpp / tests/test_i2c.cpp. The blocker is that cpp-RCP's pre-existing REQ-I2C-* 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-I2C-001 (\"i2c_mode open item — coarse high-speed decode only\"). Genuinely implemented+tested: rcp::i2c::i2c_mode_valid(v) (include/rcp/i2c.hpp) is a real constexpr function returning true for v in 0..4 and false otherwise -- tests/test_i2c.cpp's \"i2c_mode_valid accepts 0..4 and rejects everything else\" TEST_CASE (tagged REQ-I2C-001) exercises the boundary exhaustively." + }, + { + "id": "REQ-I2C-002", + "title": "rcp_ep_i2c_functional_cfg_init() zero-initializes cfg", + "text": "rcp_ep_i2c_functional_cfg_init() shall set every rcp_regmap_ep_functional_cfg_t flag in cfg->common to false, cfg->i2c_mode to RCP_EP_I2C_MODE_STANDARD (0), and cfg->ep_status, cfg->clock_divider, cfg->trail all to 0 (the three fields REQ-I2C-019's Table 49 register-block fix added), regardless of cfg's prior contents.", + "standard": "iso26262", + "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, I2C (i2c.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/i2c.hpp / tests/test_i2c.cpp. The blocker is that cpp-RCP's pre-existing REQ-I2C-* 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-I2C-002 (\"I2C compound-wait arbitrary-bit-sequence match\"). Genuinely implemented+tested: rcp::i2c::i2c_functional_cfg_init() (include/rcp/i2c.hpp) zero-initializes every I2cFunctionalCfg field -- tests/test_i2c.cpp's \"i2c_functional_cfg_init zeroes every field\" TEST_CASE (tagged REQ-I2C-002) sets every field to a non-default value first, then asserts each one back to its zero state." + }, + { + "id": "REQ-I2C-003", + "title": "rcp_ep_i2c_functional_cfg_writable() is false while HW_UNCONFIGURED", + "text": "rcp_ep_i2c_functional_cfg_writable() shall return false for state == RCP_LIFECYCLE_HW_UNCONFIGURED, for any writer, by delegating to rcp_server_field_writable() with kind RCP_LIFECYCLE_FIELD_FUNCTIONAL_W.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "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", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 8, I2C (i2c.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/i2c.hpp / tests/test_i2c.cpp. The blocker is that cpp-RCP's pre-existing REQ-I2C-* 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-I2C-003 (\"I2C controller-only raw byte-stream transfer\"). Genuinely implemented+tested: rcp::i2c::i2c_functional_cfg_writable() (include/rcp/i2c.hpp) returns false for ServerState::HwUnconfigured regardless of writer -- tests/test_i2c.cpp's \"i2c_functional_cfg_writable is false in HwUnconfigured regardless of writer\" TEST_CASE (also tagged REQ-I2C-003, sharing this numeral with the catalogued I2cEndpoint::transfer test above -- both genuinely exist and are genuinely tested at this same pre-existing id)." + }, + { + "id": "REQ-I2C-004", + "title": "rcp_ep_i2c_functional_cfg_writable() requires an authorized writer while HW_CONFIGURED", + "text": "rcp_ep_i2c_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's contents\", superseded by REQ-LIFECYCLE-030/036's authorization-gating fix (issue #198) -- the code and this module's own test (test_functional_cfg_writable_hw_configured_requires_authorization_or_discovery_stream, tests/test_ep_i2c.c) were already correct; only this entry's own text had gone stale.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "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", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 8, I2C (i2c.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/i2c.hpp / tests/test_i2c.cpp. The blocker is that cpp-RCP's pre-existing REQ-I2C-* 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-I2C-004 (\"I2C TransferComplete and Nack trigger signals\"). Genuinely implemented+tested: rcp::i2c::i2c_functional_cfg_writable() (include/rcp/i2c.hpp) returns true for ServerState::HwConfigured iff the writer is authorized via EP0/owning-stream/discovery-stream -- tests/test_i2c.cpp's \"i2c_functional_cfg_writable in HwConfigured requires EP0/owning-stream/discovery-stream\" TEST_CASE (also tagged REQ-I2C-004, sharing this numeral with the catalogued I2cEndpoint TransferComplete/Nack tests above -- both genuinely exist and are genuinely tested at this same pre-existing id)." + }, + { + "id": "REQ-I2C-005", + "title": "rcp_ep_i2c_functional_cfg_writable() requires authorization once RCP_CONFIGURED", + "text": "rcp_ep_i2c_functional_cfg_writable() shall return false for state == RCP_LIFECYCLE_RCP_CONFIGURED when writer has neither via_root_client_ep0 nor via_owning_stream set, and true when either is set.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§12.3.1.3, TC18.txt L2601-2602 (W* marker convention)", + "tc18_master_id": "TC18-12.3.1.3-005", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 8, I2C (i2c.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/i2c.hpp / tests/test_i2c.cpp. The blocker is that cpp-RCP's pre-existing REQ-I2C-* 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-I2C-005 (\"I2cErrc is a distinct error category with a non-empty message\"). Genuinely implemented+tested: rcp::i2c::i2c_functional_cfg_writable() (include/rcp/i2c.hpp) returns true for ServerState::RcpConfigured iff the writer is authorized via EP0/owning-stream (not discovery) -- tests/test_i2c.cpp's \"i2c_functional_cfg_writable in RcpConfigured requires EP0/owning-stream, not discovery\" TEST_CASE (tagged REQ-I2C-005). Unlike the 003/004/006/007 collisions below, this catalog entry's own content (I2cErrc distinct-message) is no longer tagged REQ-I2C-005 anywhere in this file at all -- that content was independently re-tagged REQ-I2C-009 (matching c-RCP's own REQ-I2C-009, \"strerror never NULL and distinct messages\") during this same rewrite pass, leaving this catalog entry's own id slot occupied by stale, no-longer-referenced content." + }, + { + "id": "REQ-I2C-006", + "title": "rcp_ep_i2c_set_mode() rejects an invalid mode value", + "text": "rcp_ep_i2c_set_mode() shall return false and leave cfg unchanged when mode is not rcp_ep_i2c_mode_valid(), regardless of state/writer.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.7.7.2 Table 49 (i2c functional configuration; RC5 renumbering of RC1's Table 46), TC18.txt L5206-5235 (i2c_mode register), writability per §12.3.1.3, TC18.txt L2601-2602 (W* marker convention)", + "tc18_master_id": "TC18-13.7.7.2-001", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 8, I2C (i2c.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/i2c.hpp / tests/test_i2c.cpp. The blocker is that cpp-RCP's pre-existing REQ-I2C-* 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-I2C-006 (\"I2cEndpoint::handle_request applies Table 33 Row 2 evt[2:0] classification before transferring\"). Genuinely implemented+tested: rcp::i2c::set_mode() (include/rcp/i2c.hpp) rejects an invalid I2cMode value regardless of authorization -- tests/test_i2c.cpp's \"set_mode rejects an invalid mode regardless of authorization\" TEST_CASE (also tagged REQ-I2C-006, sharing this numeral with the catalogued I2cEndpoint::handle_request Table 33 Row 2 dispatch tests above -- both genuinely exist and are genuinely tested at this same pre-existing id)." + }, + { + "id": "REQ-I2C-007", + "title": "rcp_ep_i2c_set_mode() rejects an unauthorized write", + "text": "rcp_ep_i2c_set_mode() shall return false and leave cfg unchanged when rcp_ep_i2c_functional_cfg_writable() does not authorize the write for state/writer, even when mode is valid.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.7.7.2 Table 49 (i2c functional configuration; RC5 renumbering of RC1's Table 46), TC18.txt L5206-5235 (i2c_mode register), writability per §12.3.1.3, TC18.txt L2601-2602 (W* marker convention)", + "tc18_master_id": "TC18-12.3.1.3-005", + "gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 8, I2C (i2c.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/i2c.hpp / tests/test_i2c.cpp. The blocker is that cpp-RCP's pre-existing REQ-I2C-* 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-I2C-007 (\"I2cEndpoint::handle_request reports config-write (evt[2:0]==111b) as not yet supported\"). Genuinely implemented+tested: rcp::i2c::set_mode() (include/rcp/i2c.hpp) rejects an unauthorized write even with a valid mode -- tests/test_i2c.cpp's \"set_mode rejects an unauthorized writer even with a valid mode\" TEST_CASE (also tagged REQ-I2C-007, sharing this numeral with the catalogued I2cEndpoint::handle_request config-write-not-supported test, whose own Catch2 bracket tag was corrected from a misplaced REQ-I2C-012 back to REQ-I2C-007 in this same batch -- both genuinely exist and are genuinely tested at this same pre-existing id)." + }, + { + "id": "REQ-GPIO-001", + "title": "rcp_ep_gpio_strerror() never returns NULL and is unique per code", + "text": "rcp_ep_gpio_strerror() shall return a non-NULL, non-empty, distinct message for each rcp_ep_gpio_errc_t value.", + "standard": "iso26262", + "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, GPIO (gpio.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/gpio.hpp / tests/test_gpio.cpp. The blocker is that cpp-RCP's pre-existing REQ-GPIO-* 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-GPIO-001 (\"GPIO payload is a 4-byte big-endian bitmask\"). Genuinely implemented+tested: rcp::gpio::gpio_category()'s message() function (include/rcp/gpio.hpp) -- cpp's error_category equivalent of rcp_ep_gpio_strerror() -- returns a distinct, non-empty message per GpioErrc value via a switch of unique string literals -- tests/test_gpio.cpp's \"GpioErrc reports a non-empty, category-correct message for every value\" TEST_CASE (tagged [REQ-GPIO-001][REQ-GPIO-039], the established dual-tag pattern) exercises every GpioErrc value 1..9 and asserts a non-empty, category-correct message for each." + }, + { + "id": "REQ-GPIO-006", + "title": "rcp_ep_gpio_apply_write() implements RCP_EP_GPIO_WRITE_REPLACE", + "text": "rcp_ep_gpio_apply_write() with evt = RCP_EP_GPIO_WRITE_REPLACE shall return request, discarding current.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.5 Table 33 (GPIO/PWM_OUT row, evt[2:0]=000b: \"The byte_msg_payload is presented at the interface\"), TC18.txt L4093", + "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 8, GPIO (gpio.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/gpio.hpp / tests/test_gpio.cpp. The blocker is that cpp-RCP's pre-existing REQ-GPIO-* 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-GPIO-006 (\"GPIO functional config block wiring\"). Genuinely implemented+tested: rcp::gpio::apply_gpio_write()'s WriteSemantics::Replace branch (include/rcp/gpio.hpp), which returns request via rcp::endpoint::apply_bitmask_write's Replace case -- tests/test_gpio.cpp's \"apply_gpio_write applies Replace/Or/And/Xor to state.values\" TEST_CASE (tagged [REQ-GPIO-006][REQ-GPIO-007][REQ-GPIO-008][REQ-GPIO-009], the established dual-tag pattern) exercises Replace directly, asserting state.values == the requested operand after a Replace write." + }, + { + "id": "REQ-GPIO-007", + "title": "rcp_ep_gpio_apply_write() implements RCP_EP_GPIO_WRITE_OR", + "text": "rcp_ep_gpio_apply_write() with evt = RCP_EP_GPIO_WRITE_OR shall return current bitwise-ORed with request.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.5 Table 33 (GPIO/PWM_OUT row, evt[2:0]=001b: \"The 'byte_msg_payload' bitwise OR 'current interface status' is written to the interface (example: with a byte_msg_payload of 0x0000 0002 the second IO pin will be set, while other IO pins remain unchanged)\"), TC18.txt L4094-4096", + "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 8, GPIO (gpio.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/gpio.hpp / tests/test_gpio.cpp. The blocker is that cpp-RCP's pre-existing REQ-GPIO-* 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-GPIO-007 (\"GpioEndpoint request-dispatch pattern\"). Genuinely implemented+tested: rcp::gpio::apply_gpio_write()'s WriteSemantics::Or branch (include/rcp/gpio.hpp) -- tests/test_gpio.cpp's \"apply_gpio_write applies Replace/Or/And/Xor to state.values\" TEST_CASE (tagged [REQ-GPIO-006][REQ-GPIO-007][REQ-GPIO-008][REQ-GPIO-009]) exercises Or directly, ORing 0xFFFF0000 into 0x0000FFFF and asserting 0xFFFFFFFF." + }, + { + "id": "REQ-GPIO-008", + "title": "rcp_ep_gpio_apply_write() implements RCP_EP_GPIO_WRITE_AND", + "text": "rcp_ep_gpio_apply_write() with evt = RCP_EP_GPIO_WRITE_AND shall return current bitwise-ANDed with request. DOCUMENTED 2026-08-14 (issue #433, code/requirement already correct): TC18 §13.7.4.1's own prose summary calls this operation 'NAND', but Table 33's own authoritative, worked-example row (the same row this entry cites) both names it 'AND' and demonstrates it with a worked example that only holds for a plain AND -- a known spec-internal editorial inconsistency, now recorded as a code comment at rcp_ep_gpio_apply_write()'s RCP_EP_GPIO_WRITE_AND case, matching this file's gpio_debounce_IO31 and PWM idle-state-bit-collision defect notes. No behavior change.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "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 (example: with a byte_msg_payload of 0xFFFF FFFE the first IO pin will be reset, while other IO pins remain unchanged)\"), 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 8, GPIO (gpio.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/gpio.hpp / tests/test_gpio.cpp. The blocker is that cpp-RCP's pre-existing REQ-GPIO-* 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-GPIO-008 (\"GpioEndpoint error propagation and GpioErrc category\"). Already taken by note: that entry's own described behavior (GpioEndpoint::handle_write error propagation and GpioErrc category) remains accurate to current code, just now exercised via tests tagged REQ-GPIO-012 and REQ-GPIO-001/-039 respectively rather than REQ-GPIO-008 itself. Genuinely implemented+tested: rcp::gpio::apply_gpio_write()'s WriteSemantics::And branch (include/rcp/gpio.hpp) -- tests/test_gpio.cpp's \"apply_gpio_write applies Replace/Or/And/Xor to state.values\" TEST_CASE (tagged [REQ-GPIO-006][REQ-GPIO-007][REQ-GPIO-008][REQ-GPIO-009]) exercises And directly (0x0F0F0F0F AND 0xFFFFFFFF -> 0x0F0F0F0F after the preceding Or)." + }, + { + "id": "REQ-GPIO-009", + "title": "rcp_ep_gpio_apply_write() implements RCP_EP_GPIO_WRITE_XOR", + "text": "rcp_ep_gpio_apply_write() with evt = RCP_EP_GPIO_WRITE_XOR shall return current bitwise-XORed with request.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "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 (example: with a byte_msg_payload of 0x0000 0002 the second IO pin will be toggled, while other IO pins remain unchanged)\"), 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 8, GPIO (gpio.hpp) module). The behavior itself is genuinely implemented and tested in include/rcp/gpio.hpp / tests/test_gpio.cpp. The blocker is that cpp-RCP's pre-existing REQ-GPIO-* 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-GPIO-009 (\"A write to a pin configured as input leaves that pin's value unchanged\"). Note: that entry's own content is not orphaned -- it has been correctly and separately re-derived, re-tagged, and re-catalogued verbatim from c-RCP under this batch's new REQ-GPIO-037 entry (same title, same tc18_master_id TC18-13.7.4.3-004), genuinely implemented via rcp::gpio::apply_gpio_write()'s input-pin masking and tested by three TEST_CASEs tagged [REQ-GPIO-037]. Genuinely implemented+tested: rcp::gpio::apply_gpio_write()'s WriteSemantics::Xor branch (include/rcp/gpio.hpp) -- tests/test_gpio.cpp's \"apply_gpio_write applies Replace/Or/And/Xor to state.values\" TEST_CASE (tagged [REQ-GPIO-006][REQ-GPIO-007][REQ-GPIO-008][REQ-GPIO-009]) exercises Xor directly (0x0F0F0F0F XOR 0xFFFFFFFF -> 0xF0F0F0F0)." + }, + { + "id": "REQ-GPIO-002", + "title": "rcp_ep_gpio_pin_index_valid() bounds pin indices to 0..31", + "text": "rcp_ep_gpio_pin_index_valid() shall return true if and only if pin_index is strictly less than RCP_EP_GPIO_MAX_PINS (32).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.7.4.1 (\"Each GPIO endpoint can handle up to 32 IOs.\"), TC18.txt L4789", + "tc18_master_id": "TC18-13.7.4.1-001", + "gap": "Confirmed absent (2026-08-22, cpp-RCP Phase 6 batch 8, GPIO (gpio.hpp) module): include/rcp/gpio.hpp has no standalone function matching rcp_ep_gpio_pin_index_valid()'s contract (a reusable bool(uint8_t) bounds predicate), and tests/test_gpio.cpp has zero TEST_CASEs bracket-tagged [REQ-GPIO-002] (grep-verified: `grep -c '\\[REQ-GPIO-002\\]' tests/test_gpio.cpp` -> 0). cpp-RCP's own top-of-file manifest (both files) DOES carry a `// fusa:req REQ-GPIO-002` / `// fusa:test REQ-GPIO-002` line, but this is an orphaned claim -- no code or test backs it specifically; not rubber-stamped into a catalog entry here. The equivalent bounds check (`pin_index >= kMaxPins`) IS inlined ad hoc at each call site that needs it (set_pin_property, set_pin_trigger, trigger_signal_number), so the underlying safety property holds dispersedly, but there is no single reusable, independently-tested primitive matching c-RCP's contract -- this batch does not add one, since the methodology restricts this pass to tag/test-only edits over already-implemented production code, not new production code. cpp-RCP's own pre-existing REQ-GPIO-002 catalog entry (\"GPIO write semantics: generic combinators\") occupies this id; that entry's own described content (apply_gpio_write's Replace/Or/And/Xor combinators) has itself since been correctly re-derived and split across this batch's new REQ-GPIO-006/007/008/009 collision-gap filings, leaving REQ-GPIO-002's own catalog text stale/orphaned at this numeral -- left untouched here per the collision-avoidance policy, not itself re-filed as a separate finding." + }, + { + "id": "REQ-GPIO-003", + "title": "rcp_ep_gpio_pin_mask() derives a single-bit mask, or 0 for an invalid index", + "text": "rcp_ep_gpio_pin_mask() shall return (1u << pin_index) for a valid pin_index, and 0 for a pin_index that is not rcp_ep_gpio_pin_index_valid().", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.7.4.1 (\"Each GPIO pin can be assigned to a bit position of the byte_msg_payload... In case the EP supports less than 32 pins, the least-significant bits are used.\"), TC18.txt L4797-4798", + "tc18_master_id": "TC18-13.7.4.1-004", + "gap": "Confirmed absent (2026-08-22, cpp-RCP Phase 6 batch 8, GPIO (gpio.hpp) module): no standalone pin_mask()-equivalent function exists in include/rcp/gpio.hpp; the single-bit mask (1u << pin) is derived inline within evaluate_gpio_triggers's bit-test loop and elsewhere but is not exposed as a named, independently-testable unit. tests/test_gpio.cpp has zero TEST_CASEs bracket-tagged [REQ-GPIO-003] (grep-verified). cpp-RCP's own pre-existing REQ-GPIO-003 catalog entry (\"GPIO write semantics: saturating Add/Subtract\") occupies this id; that entry's own content has since been correctly re-derived and catalogued as this batch's new REQ-GPIO-010/011 entries. Left untouched here." + }, + { + "id": "REQ-GPIO-004", + "title": "rcp_ep_gpio_pin_get() reads one bit of a bitmask", + "text": "rcp_ep_gpio_pin_get() shall return true if and only if bitmask's bit at pin_index is set, and shall return false (not an error) for an invalid pin_index.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.7.4.1 (\"A GPIO endpoint maps bits from a byte_msg_payload to physical pins.\"), TC18.txt L4788", + "tc18_master_id": "TC18-13.7.4.1-004", + "gap": "Confirmed absent (2026-08-22, cpp-RCP Phase 6 batch 8, GPIO (gpio.hpp) module): no standalone pin_get()-equivalent function exists in include/rcp/gpio.hpp; the single-bit read (`(values >> pin) & 1u`) is inlined at each call site (evaluate_gpio_triggers, etc.) rather than exposed as a named, independently-testable unit. tests/test_gpio.cpp has zero TEST_CASEs bracket-tagged [REQ-GPIO-004] (grep-verified). cpp-RCP's own pre-existing REQ-GPIO-004 catalog entry (\"GPIO write semantics: Reserved rejected, Reconfigure retargets directions\") occupies this id; that entry's own content has since been correctly re-derived and catalogued as this batch's new REQ-GPIO-012/013 entries. Left untouched here." + }, + { + "id": "REQ-GPIO-005", + "title": "rcp_ep_gpio_write_semantics_valid() accepts exactly 0..7", + "text": "rcp_ep_gpio_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", + "tc18": "§13.5 Table 33 (GPIO/PWM_OUT row, evt[2:0]=000b-111b), TC18.txt L4093-4115", + "tc18_master_id": "TC18-13.5-001", + "gap": "Confirmed divergence (2026-08-22, cpp-RCP Phase 6 batch 8, GPIO (gpio.hpp) module): cpp has no standalone bool write_semantics_valid(uint8_t) function anywhere in include/rcp/gpio.hpp. Instead rcp::endpoint::write_semantics_of(uint8_t evt_op) (include/rcp/endpoint.hpp -- shared by GPIO and PWM_OUT, outside this batch's edit scope of gpio.hpp/test_gpio.cpp) unconditionally masks its input to the low 3 bits (`evt_op & 0x07`) before converting to the WriteSemantics enum, making an 'invalid' (>7) raw value structurally unrepresentable rather than validated-and-rejected -- a different architecture from c-RCP's explicit uint8_t validity predicate. tests/test_gpio.cpp has zero TEST_CASEs bracket-tagged [REQ-GPIO-005] (grep-verified), and endpoint::write_semantics_of's own masking behavior (if tested at all) lives in test_endpoint.cpp, out of this GPIO-scoped batch's file scope. cpp-RCP's own pre-existing REQ-GPIO-005 catalog entry (\"GPIO per-pin change/rising/falling trigger signals\") occupies this id; that entry's own content has since been correctly re-derived and split across this batch's new REQ-GPIO-014/015/016/017 entries. Left untouched here." + }, + { + "id": "REQ-ADC-001", + "title": "rcp_ep_adc_response_value_count() returns half a request's read_size", + "text": "rcp_ep_adc_response_value_count() shall return read_size / RCP_EP_ADC_VALUE_LEN when read_size is even, and 0 when read_size is odd.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.7.9.3 (\"Responses contain as much measurement values as requested by half the read size of a request.\"), TC18.txt L5162-5163", + "tc18_master_id": "TC18-13.7.9.3-002", + "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-001 (\"ADC arithmetic-mean averaging combinator\"). Genuinely implemented+tested: rcp::adc::response_value_count(read_size) (include/rcp/adc.hpp) is a real function returning read_size/kAdcValueLen for even read_size and 0 for odd -- tests/test_adc.cpp's \"response_value_count returns half a request's read_size\" TEST_CASE (tagged REQ-ADC-001) exercises 0, 2, and 16." + }, + { + "id": "REQ-ADC-002", + "title": "rcp_ep_adc_average_interval() computes the arithmetic mean of its raw samples", + "text": "rcp_ep_adc_average_interval() shall, given sample_count samples none of which equal RCP_EP_PWM_IN_NO_SIGNAL, return a value equal to their arithmetic mean, rounded down.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.7.9.1 (\"...further samples are taken with a timely distance of one 'adc_sample_interval'... For the readings acquired during the averaging interval given in number of samples... the average is calculated.\"), TC18.txt L5036-5040", + "tc18_master_id": "TC18-13.7.9.1-006", + "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-002 (\"ADC three-level averaging model\"). Genuinely implemented+tested: rcp::adc::average_interval(samples) (include/rcp/adc.hpp) computes the arithmetic mean of a raw sample set -- tests/test_adc.cpp's \"average_interval computes the arithmetic mean of raw samples\" and \"average_interval averages samples at the 16-bit ceiling without overflow\" TEST_CASEs (both tagged REQ-ADC-002) exercise the mean computation and its overflow-safety boundary." + }, + { + "id": "REQ-ADC-003", + "title": "rcp_ep_adc_average_interval() returns RCP_EP_PWM_IN_NO_SIGNAL with a zero timestamp when sample_count is 0", + "text": "rcp_ep_adc_average_interval() shall return value == RCP_EP_PWM_IN_NO_SIGNAL and timestamp == 0 when sample_count == 0. RESOLVED (issue #184, c-RCP-AUDIT-05), left honestly uncited rather than force-cited: TC18's ADC chapter (§13.7.9) never discusses a raw-sample timeout, a \"no signal\" condition, or any payload-sentinel convention at all -- unlike PWM_IN (see REQ-PWM-047's own resolution note), TC18 does not even describe the failure mode this value represents for ADC. Reusing RCP_EP_PWM_IN_NO_SIGNAL here (ep_adc.h's own documented choice, rather than declaring a second, inconsistent sentinel) is entirely this codebase's own invention with no TC18 basis to cite, real or drifted.", + "standard": "iso26262", + "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-003 (\"ADC request-driven sampling only\"). Genuinely implemented+tested: rcp::adc::average_interval({}) (include/rcp/adc.hpp) returns kAdcNoSignal with a zero timestamp for an empty sample set -- tests/test_adc.cpp's \"average_interval returns kAdcNoSignal with a zero timestamp when sample_count is 0\" TEST_CASE (tagged REQ-ADC-003) exercises exactly this." + }, + { + "id": "REQ-ADC-004", + "title": "rcp_ep_adc_average_interval() excludes RCP_EP_PWM_IN_NO_SIGNAL samples from its arithmetic mean", + "text": "rcp_ep_adc_average_interval() shall exclude every sample whose value equals RCP_EP_PWM_IN_NO_SIGNAL from its arithmetic mean. SPLIT 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch): this id previously also bundled the 'return NO_SIGNAL only when every sample times out' clause under the same id; that is now REQ-ADC-041, its own independently-tested behaviour (test_average_interval_skips_no_signal_samples proves this exclusion clause, test_average_interval_all_no_signal_is_no_signal proves REQ-ADC-041's propagation clause -- both already existed as separate test functions before this split, confirming the bundling). RESOLVED (issue #184, c-RCP-AUDIT-05), left honestly uncited rather than force-cited: same basis as REQ-ADC-003 -- TC18's ADC chapter defines no timeout/no-signal concept and no payload-sentinel convention to cite; this exclusion rule is this codebase's own design for a failure mode TC18 does not address, not a TC18 citation gap.", + "standard": "iso26262", + "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-004 (\"ADC ExternalTrigger cadence pattern\"). Genuinely implemented+tested: rcp::adc::average_interval(samples) (include/rcp/adc.hpp) excludes kAdcNoSignal-valued samples from its arithmetic mean -- tests/test_adc.cpp's \"average_interval excludes kAdcNoSignal samples from its arithmetic mean\" TEST_CASE (tagged REQ-ADC-004) proves the mean of {10, kAdcNoSignal, 30} is 20, not influenced by the sentinel." + }, + { + "id": "REQ-ADC-005", + "title": "rcp_ep_adc_average_interval() reports the timestamp of the last sample that fed the mean", + "text": "rcp_ep_adc_average_interval() shall set the returned timestamp to the timestamp of the last samples[i] not equal to RCP_EP_PWM_IN_NO_SIGNAL, or, when every sample timed out, to samples[sample_count - 1].timestamp, for any sample_count > 0.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.7.9.3 (\"If the response includes a timestamp, it shall represent the point in time when the last sample that was used for the first average value that is included in the response has been captured.\"), TC18.txt L5143-5145", + "tc18_master_id": "TC18-13.7.9.2-006", + "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-005 (\"ADC no-signal handling for a missing triggered capture\"). Genuinely implemented+tested: rcp::adc::average_interval(samples) (include/rcp/adc.hpp) reports the timestamp of the last sample that actually fed the mean (not the interval's literal last sample) -- tests/test_adc.cpp's \"average_interval reports the timestamp of the last sample that fed the mean\" TEST_CASE (tagged REQ-ADC-005) proves this against a trailing kAdcNoSignal sample." + }, + { + "id": "REQ-ADC-006", + "title": "rcp_ep_adc_collect_response_values() packs averaged values in capture order", + "text": "rcp_ep_adc_collect_response_values() shall copy avg_values[i].value into out_values[i] for i in 0..min(avg_count, value_count), preserving capture order.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.7.9.1 (\"...the COMBINE_NR_VAL defines how many measurement values (i.e. averaging results) will be put in one response frame.\"), TC18.txt L5040-5042", + "tc18_master_id": "TC18-13.7.9.3-002", + "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-006 (\"AdcErrc is a distinct error category with a non-empty message\"). Genuinely implemented+tested: rcp::adc::collect_response_values(avg, n, out) (include/rcp/adc.hpp) copies averaged values into out_values in capture order -- 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, since the same call also proves the sentinel-passthrough clause) exercises this against a 3-element set including a kAdcNoSignal entry, and a second TEST_CASE at REQ-ADC-006 alone (line ~503) also covers this id." + }, + { + "id": "REQ-ADC-007", + "title": "rcp_ep_adc_collect_response_values() packs exactly value_count values when enough are available", + "text": "rcp_ep_adc_collect_response_values() shall, when avg_count >= value_count, write exactly value_count values -- the leading ones -- and return value_count.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.7.9.2 Table 54 (\"adc_combine_avg_values ... Nr of output values to be combined in one response\"), TC18.txt L5110-5111", + "tc18_master_id": "TC18-13.7.9.3-002", + "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-007 (\"encode_adc_value encodes a single measurement as a 16-bit big-endian wire value\"). Genuinely implemented+tested: rcp::adc::collect_response_values(avg, value_count, out) (include/rcp/adc.hpp), when avg.size() >= value_count, writes exactly value_count values -- the leading ones -- and returns value_count -- tests/test_adc.cpp's \"collect_response_values packs exactly value_count values -- the leading ones -- when more averages are available than requested\" TEST_CASE (tagged REQ-ADC-007, added in this same batch to close a genuine test-coverage gap: the pre-existing tests only exercised the avg.size()==value_count and avg.size()value_count) proves this against a 4-entry set requesting only 2." + }, + { + "id": "REQ-ADC-008", + "title": "rcp_ep_adc_collect_response_values() reports a short count without touching the unwritten entries", + "text": "rcp_ep_adc_collect_response_values() shall, when avg_count < value_count, write avg_count values, return avg_count, and leave out_values[avg_count..value_count) untouched.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§13.7.9.2 (\"When adc_combine_avg_values < adc_avg_intervals_per_request, then there are multiple responses per request execution.\"), TC18.txt L5132-5133", + "tc18_master_id": "TC18-13.7.9.3-002", + "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-008 (\"AdcEndpoint::handle_request applies Table 33 Row 2 evt[2:0] classification before sampling\") (this entry also carries a pre-existing severity:cybersecurity marker, left untouched). Genuinely implemented+tested: rcp::adc::collect_response_values(avg, value_count, out) (include/rcp/adc.hpp), when avg.size() < value_count, writes avg.size() values, returns avg.size(), and leaves the remaining out_values entries untouched -- tests/test_adc.cpp's \"collect_response_values reports a short count without touching unwritten entries\" TEST_CASE (tagged REQ-ADC-008) exercises this against a 2-entry set requesting 5." + }, + { + "id": "REQ-ADC-009", + "title": "rcp_ep_adc_collect_response_values() carries RCP_EP_PWM_IN_NO_SIGNAL through verbatim", + "text": "rcp_ep_adc_collect_response_values() shall copy an avg_values[i].value equal to RCP_EP_PWM_IN_NO_SIGNAL into its own out_values slot unchanged, never substituting or averaging it away. RESOLVED (issue #184, c-RCP-AUDIT-05), left honestly uncited rather than force-cited: same basis as REQ-ADC-003/004 -- TC18's §13.7.9.1 COMBINE_NR_VAL rule (multiple averaged values packed into one response) has no companion rule anywhere for a per-position failure marker; propagating the sentinel through this packing step verbatim is this codebase's own choice for a case TC18 leaves unaddressed, not a TC18 citation gap.", + "standard": "iso26262", + "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." } ] -} \ No newline at end of file +} diff --git a/.fusa-reqs.json b/.fusa-reqs.json index 55bc72c..c2116cb 100644 --- a/.fusa-reqs.json +++ b/.fusa-reqs.json @@ -6802,6 +6802,1202 @@ "status": "implemented", "tc18": "§13.7.12.2 Table 58, TC18.txt L5916-5961", "tc18_master_id": "TC18-13.7.12.2-001" + }, + { + "id": "REQ-I2C-008", + "title": "rcp_ep_i2c_set_mode() applies a valid, authorized write", + "text": "rcp_ep_i2c_set_mode() shall set cfg->i2c_mode to mode and return true when mode is rcp_ep_i2c_mode_valid() and rcp_ep_i2c_functional_cfg_writable() authorizes the write for state/writer.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.7.2 Table 49 (i2c functional configuration; RC5 renumbering of RC1's Table 46), TC18.txt L5206-5235 (i2c_mode register), writability per §12.3.1.3, TC18.txt L2601-2602 (W* marker convention)", + "tc18_master_id": "TC18-13.7.7.2-001" + }, + { + "id": "REQ-I2C-009", + "title": "rcp_ep_i2c_strerror() never returns NULL and returns distinct messages", + "text": "rcp_ep_i2c_strerror() shall return a non-NULL, non-empty message for every rcp_ep_i2c_errc_t value (including an out-of-range value), with a distinct message per defined error code.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-I2C-010", + "title": "rcp_ep_i2c_encode_transfer_request() encodes the requested RCP-level direction", + "text": "rcp_ep_i2c_encode_transfer_request() shall produce an ACF_ABB frame with evt == 0, byte_bus_id == byte_bus_id, transaction_num == transaction_num, payload exactly tx_data[0..tx_len), and op selected by direction: op == RCP_ACF_OP_READ (wire op=0, the payload-bearing-response direction) with read_size_or_segment_num == read_size for RCP_EP_I2C_DIR_READ, and op == RCP_ACF_OP_WRITE (wire op=1) with read_size_or_segment_num == 0 for RCP_EP_I2C_DIR_WRITE. The I2C-bus-level R/W bit inside the payload's address octet(s) is independent of op and shall be round-tripped unmodified.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.7.3 Figure 30 (i2c request format; RC5 renumbering of RC1's Figure 29), TC18.txt L5240-5257; \"no channel selector\" per §13.5 Table 33 (I2C's row-2 group, only evt=111b defined), TC18.txt L4083-4093", + "tc18_master_id": "TC18-13.7.7.3-001" + }, + { + "id": "REQ-I2C-011", + "title": "rcp_ep_i2c_decode_transfer_request() round-trips payload, direction and read_size", + "text": "rcp_ep_i2c_decode_transfer_request() shall, given a frame produced by rcp_ep_i2c_encode_transfer_request() and the same byte_bus_id, return RCP_EP_I2C_OK and recover the original tx bytes (address byte(s) included, unparsed), the encoded direction, the requested read_size (0 for RCP_EP_I2C_DIR_WRITE, whose header slot is a segment_num) and transaction_num unchanged, byte for byte.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.7.3 Figure 30 (i2c request format; RC5 renumbering of RC1's Figure 29), TC18.txt L5240-5257; §13.7.7.1 (\"Requests are accepted in ACF_ABB and ACF_GBB.\"), TC18.txt L5201; evt[2:0] validation per §13.5 Table 33 (I2C's row-2 group, only evt=111b defined), TC18.txt L4083-4093", + "tc18_master_id": "TC18-13.7.7.3-001" + }, + { + "id": "REQ-I2C-012", + "title": "rcp_ep_i2c_decode_transfer_request() rejects a malformed or misaddressed frame", + "text": "rcp_ep_i2c_decode_transfer_request() shall return RCP_EP_I2C_ERR_SHORT_FRAME for a frame too short for the ACF_ABB fixed header or its declared payload length, RCP_EP_I2C_ERR_BAD_MSG_TYPE for a non-ACF_ABB frame, RCP_EP_I2C_ERR_WRONG_BUS when byte_bus_id != expected_bus_id, and RCP_EP_I2C_ERR_BAD_EVT when evt[2:0] is not 0b000 -- TC18 §13.5 Table 33's only legal value for a plain request in I2C's endpoint-type row. Corrected 2026-08-18 (c-RCP-18-tracker, issue #533 REQ-I2C-* atomicity audit): this entry previously also asserted (a) that every other evt value \"shall be rejected with error code UNSUPPORTED_CMD at the dispatch layer\" -- a different layer's behavior this function/module does not itself implement (ep_i2c.c has no rcp_ep_i2c_wire_error()-style mapper, unlike ep_pwm.c's/ep_gpio.c's own RESERVED_EVT->RCP_ERROR_UNSUPPORTED_CMD mappers; the caller-obligation framing already used correctly in ep_i2c.h's own doc comment is what that clause should have been, not a testable contract of this function), and (b) \"It shall accept BOTH op senses ... report which via *out_direction\" -- a distinct, separately-tested success-path assertion unrelated to this entry's own reject-malformed-frame contract, now split into REQ-I2C-023.", + "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-I2C-013", + "title": "rcp_ep_i2c_encode_response() encodes the direction's op and the right framing", + "text": "rcp_ep_i2c_encode_response() shall produce an ACF_ABB frame when timed is false and an ACF_GBB frame with mtv == RCP_ACF_MTV_VALID and message_timestamp == timestamp when timed is true, in both cases with evt == 0 and op selected by direction: op == RCP_ACF_OP_READ with payload exactly rx_data[0..rx_len) for RCP_EP_I2C_DIR_READ (a read response has a byte_msg_payload), and op == RCP_ACF_OP_WRITE with no payload for RCP_EP_I2C_DIR_WRITE (a write response does not). Corrected 2026-08-18 (c-RCP-18-tracker, issue #533 REQ-I2C-* atomicity audit): this entry previously also asserted the reject-invalid-input contract (\"shall return a zeroed rcp_bytes_t when direction is not rcp_ep_i2c_dir_valid() or when rx_len != 0 with RCP_EP_I2C_DIR_WRITE\"), a separate function-wide guard clause bundled with the encode-success contract above -- split into REQ-I2C-024, matching this module's own sibling split for rcp_ep_i2c_encode_transfer_request() (REQ-I2C-010 encode-success vs. REQ-I2C-018 reject-invalid-inputs).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.7.3 Figure 30 (i2c request format; RC5 renumbering of RC1's Figure 29), TC18.txt L5240-5257; §13.7.7.3 (\"The byte msg payload is the I2C payload including the address. The I2C endpoint does not know whether there is a 7- or 10-bit address, since the endpoint is just transparent.\"), TC18.txt L5241-5242", + "tc18_master_id": "TC18-13.7.7.3-001" + }, + { + "id": "REQ-I2C-014", + "title": "rcp_ep_i2c_decode_response() round-trips an untimed response", + "text": "rcp_ep_i2c_decode_response() shall, given a frame produced by rcp_ep_i2c_encode_response() with timed = false and the same byte_bus_id, return RCP_EP_I2C_OK, recover the original rx payload bytes, the response's direction 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.7.3 Figure 30 (i2c request format; RC5 renumbering of RC1's Figure 29), TC18.txt L5240-5257; response timed/untimed ACF_GBB/ACF_ABB convention shared with every prior endpoint type", + "tc18_master_id": "TC18-13.7.7.3-001" + }, + { + "id": "REQ-I2C-015", + "title": "rcp_ep_i2c_decode_response() round-trips a timed response", + "text": "rcp_ep_i2c_decode_response() shall, given a frame produced by rcp_ep_i2c_encode_response() with timed = true, the same byte_bus_id, and a timestamp, return RCP_EP_I2C_OK, recover the original rx payload bytes, the response's direction 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.7.3 Figure 30 (i2c request format; RC5 renumbering of RC1's Figure 29), TC18.txt L5240-5257; response timed/untimed ACF_GBB/ACF_ABB convention shared with every prior endpoint type", + "tc18_master_id": "TC18-13.7.7.3-001" + }, + { + "id": "REQ-I2C-016", + "title": "rcp_ep_i2c_decode_response() rejects a malformed or misaddressed frame", + "text": "rcp_ep_i2c_decode_response() shall return RCP_EP_I2C_ERR_SHORT_FRAME for a frame too short for its applicable ACF fixed header and RCP_EP_I2C_ERR_WRONG_BUS when byte_bus_id != expected_bus_id.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.7.3 Figure 30 (i2c request format; RC5 renumbering of RC1's Figure 29), TC18.txt L5240-5257, TC18.txt L5257 -- general ACF frame-validation basis for the response wire format", + "tc18_master_id": "TC18-13.7.7.3-001" + }, + { + "id": "REQ-I2C-017", + "title": "rcp_ep_i2c_dir_valid() accepts exactly the two defined directions", + "text": "rcp_ep_i2c_dir_valid() shall return true for RCP_EP_I2C_DIR_WRITE and RCP_EP_I2C_DIR_READ and false for any other value.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.7.1 (\"The Client can request the I²C endpoint to send one or more bytes... Requests are accepted in ACF_ABB and ACF_GBB.\"), TC18.txt L5199-5201 -- I2C's genuinely bidirectional read/write op sense", + "tc18_master_id": "TC18-13.7.7.1-002" + }, + { + "id": "REQ-I2C-018", + "title": "rcp_ep_i2c_encode_transfer_request() rejects unencodable direction/read_size inputs", + "text": "rcp_ep_i2c_encode_transfer_request() shall return a zeroed rcp_bytes_t (data == NULL) when direction is not rcp_ep_i2c_dir_valid(), when read_size exceeds RCP_EP_I2C_MAX_READ_SIZE (the ACF header read_size slot is 12 bits wide), or when read_size != 0 with direction RCP_EP_I2C_DIR_WRITE (in the write sense that slot carries a segment_num, not a read_size).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.7.3 Figure 30 (i2c request format; RC5 renumbering of RC1's Figure 29), TC18.txt L5240-5257; \"no channel selector\" per §13.5 Table 33 (I2C's row-2 group, only evt=111b defined), TC18.txt L4083-4093", + "tc18_master_id": "TC18-13.7.7.3-001" + }, + { + "id": "REQ-I2C-020", + "title": "I2C payload carries the address and the endpoint stays address-format agnostic", + "text": "The I2C endpoint's request codec shall treat the byte_msg_payload as the complete I2C payload INCLUDING the target address and shall not interpret, validate or rewrite that address -- remaining transparent to whether the transfer uses a 7-bit or a 10-bit address, per TC18 13.7.7.3.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.7.3, TC18.txt L5241-5243", + "tc18_master_id": "TC18-13.7.7.3-001" + }, + { + "id": "REQ-I2C-021", + "title": "rcp_ep_i2c_render_registers() implements the §12.7.1 configuration-read for I2C's Table 46 block", + "text": "FIXED 2026-08-11 (c-RCP-AUDIT-06, issue #256 Group I): TC18 §12.7.1 Figure 18 defines one generic configuration request -- evt[2:0] = 111b, byte_msg_payload = a relative register start address within the addressed endpoint's EP_func section followed by configuration data -- usable against every endpoint type. rcp_ep_i2c_decode_transfer_request() already correctly rejected evt[2:0] = 111b as not a plain transfer (RCP_EP_I2C_ERR_BAD_EVT, via acf.h's rcp_acf_evt_row2_is_plain()), but no counterpart function rendered this endpoint's own Table 46 block at all. rcp_ep_i2c_render_registers() shall serialize cfg's whole EP_func register block into out[0..RCP_EP_I2C_EP_FUNC_LEN) at the corrected (not the table's own colliding-printed) per-register offsets -- RCP_EP_I2C_REG_EP_LEN/_RESERVED_01/_EP_ENABLE_CLR/_EP_OPTIONS/_BASE_CLK/_EP_STATUS/_CLOCK_DIVIDER/_MODE/_TRAIL -- rendering the read-only i2c_base_clk register as a constant 0 (no real clock source modelled). Corrected 2026-08-18 (c-RCP-18-tracker, issue #533 REQ-I2C-* atomicity audit): this entry previously also bundled rcp_ep_i2c_encode_reconfig_request()'s own separate contract -- a different function encoding the wire REQUEST rather than rendering the register block itself -- now split into REQ-I2C-025.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.7.1 Configuration of endpoints + Figure 19 (renumbered from Figure 18 by the RC5 rebaseline), TC18.txt L2844-2860", + "tc18_master_id": "TC18-12.7.1-002" + }, + { + "id": "REQ-I2C-022", + "title": "rcp_ep_i2c_apply_reconfig() applies the addressed configuration write", + "text": "FIXED 2026-08-11 (c-RCP-AUDIT-06, issue #256 Group I): rcp_ep_i2c_apply_reconfig() decodes the address+data payload TC18 §12.7.1 defines and patches cfg's Table 46 register block at octet granularity, then adopts the whole block atomically -- a write whose start_address+length exceeds RCP_EP_I2C_EP_FUNC_LEN is rejected and cfg left entirely unchanged (RCP_EP_I2C_RECONFIG_ERR_OUT_OF_RANGE), matching §12.7.1's own 'such a payload is to be ignored' rule; octets landing on a read-only register (EP_LEN, the reserved octet, or base_clk) are silently skipped while the rest of the span is still applied. Corrected 2026-08-18 (c-RCP-18-tracker, issue #533 REQ-I2C-* atomicity audit): this entry previously also asserted rcp_ep_i2c_reconfig_strerror()'s own separate never-NULL contract -- a different function -- now split into REQ-I2C-026.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.7.1 Configuration of endpoints, TC18.txt L2844-2860", + "tc18_master_id": "TC18-12.7.1-003" + }, + { + "id": "REQ-I2C-023", + "title": "rcp_ep_i2c_decode_transfer_request() accepts both op senses and reports which", + "text": "rcp_ep_i2c_decode_transfer_request() shall accept BOTH RCP_ACF_OP_READ and RCP_ACF_OP_WRITE as valid -- an I2C transfer is half duplex and genuinely either-directional, so neither op sense is malformed -- and report the decoded direction via *out_direction, independent of the frame's evt/byte_bus_id validity checks. Split 2026-08-18 from REQ-I2C-012 (c-RCP-18-tracker, issue #533 REQ-I2C-* atomicity audit): this is a distinct success-path assertion, not part of that entry's reject-malformed-frame contract.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.7.1 (\"The Client can request the I²C endpoint to send one or more bytes... Requests are accepted in ACF_ABB and ACF_GBB.\"), TC18.txt L5199-5201 -- I2C's genuinely bidirectional read/write op sense", + "tc18_master_id": "TC18-13.7.7.1-002" + }, + { + "id": "REQ-I2C-024", + "title": "rcp_ep_i2c_encode_response() rejects unencodable direction/rx_len inputs", + "text": "rcp_ep_i2c_encode_response() shall return a zeroed rcp_bytes_t (data == NULL) when direction is not rcp_ep_i2c_dir_valid(), or when rx_len != 0 with direction RCP_EP_I2C_DIR_WRITE (a write response has no byte_msg_payload). Split 2026-08-18 from REQ-I2C-013 (c-RCP-18-tracker, issue #533 REQ-I2C-* atomicity audit), matching REQ-I2C-010/REQ-I2C-018's own established encode-success/reject-invalid split for the sibling rcp_ep_i2c_encode_transfer_request().", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.7.3 Figure 30 (i2c request format; RC5 renumbering of RC1's Figure 29), TC18.txt L5240-5257", + "tc18_master_id": "TC18-13.7.7.3-001" + }, + { + "id": "REQ-I2C-025", + "title": "rcp_ep_i2c_encode_reconfig_request() encodes the §12.7.1 configuration-write request", + "text": "rcp_ep_i2c_encode_reconfig_request() shall encode an ACF_ABB write request (op == RCP_ACF_OP_WRITE, evt[2:0] == 111b) addressed to byte_bus_id, with payload equal to start_address (16-bit big-endian) followed by data[0..data_len), matching PWM_OUT's/GPIO's/SPI's own encode_reconfig_request() shape, and shall return a zeroed rcp_bytes_t (data == NULL) when data_len is 0 or data is NULL, when the encoded payload would exceed RCP_ACF_MAX_PAYLOAD, or on allocation failure. Split 2026-08-18 from REQ-I2C-021 (c-RCP-18-tracker, issue #533 REQ-I2C-* atomicity audit).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.7.1 Configuration of endpoints + Figure 19 (renumbered from Figure 18 by the RC5 rebaseline), TC18.txt L2844-2860", + "tc18_master_id": "TC18-12.7.1-002" + }, + { + "id": "REQ-I2C-026", + "title": "rcp_ep_i2c_reconfig_strerror() never returns NULL and returns distinct messages", + "text": "rcp_ep_i2c_reconfig_strerror() shall return a distinct, non-NULL, human-readable message for each of RCP_EP_I2C_RECONFIG_OK, RCP_EP_I2C_RECONFIG_ERR_SHORT, and RCP_EP_I2C_RECONFIG_ERR_OUT_OF_RANGE, and a non-NULL message for any other value. Split 2026-08-18 from REQ-I2C-022 (c-RCP-18-tracker, issue #533 REQ-I2C-* atomicity audit), matching this codebase's own established strerror-family convention (REQ-I2C-009, REQ-GPIO-039, REQ-PWM-024, et al.).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.7.1 Configuration of endpoints, TC18.txt L2844-2860", + "tc18_master_id": "TC18-12.7.1-003" + }, + { + "id": "REQ-GPIO-010", + "title": "rcp_ep_gpio_apply_write() implements saturating RCP_EP_GPIO_WRITE_ADD", + "text": "rcp_ep_gpio_apply_write() with evt = RCP_EP_GPIO_WRITE_ADD shall return current + request when that sum does not exceed 0xFFFFFFFF, and shall return 0xFFFFFFFF (saturating, not wrapping) when it would.", + "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" + }, + { + "id": "REQ-GPIO-011", + "title": "rcp_ep_gpio_apply_write() implements saturating RCP_EP_GPIO_WRITE_SUB as request minus current", + "text": "rcp_ep_gpio_apply_write() with evt = RCP_EP_GPIO_WRITE_SUB shall return request - current when current <= request, and shall return 0 (saturating, not wrapping) when current > request.", + "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" + }, + { + "id": "REQ-GPIO-012", + "title": "rcp_ep_gpio_apply_write() treats RCP_EP_GPIO_WRITE_RESERVED4 as a no-op", + "text": "IMPLEMENTED (FIXED 2026-08-14, issue #426): rcp_ep_gpio_apply_write() with evt = RCP_EP_GPIO_WRITE_RESERVED4 returns current unchanged, regardless of request (the 'ignored' half of Table 33's two-part reserved-value rule). SPLIT 2026-08-18 (c-RCP-18-tracker, REQ-GPIO-* atomicity audit, issue #533): the 'err-response' half of that same rule -- rcp_ep_gpio_decode_write_request()'s own RCP_EP_GPIO_ERR_RESERVED_EVT detection and rcp_ep_gpio_wire_error()'s mapping of that code to RCP_ERROR_UNSUPPORTED_CMD, both previously bundled into this same entry alongside three different functions' behavior under one id -- are now their own ids, REQ-GPIO-045 and REQ-GPIO-046 respectively. The dispatch-wiring end-to-end proof (issue #469, gpio_dispatch_handler() in test_tc18_gaps_ep.c) remains a test-fixture-level integration proof of all three, not a separate requirement of its own.", + "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" + }, + { + "id": "REQ-GPIO-013", + "title": "rcp_ep_gpio_apply_reconfig() applies an addressed write into the GPIO EP_func register block", + "text": "CORRECTED 2026-08-11 (c-RCP-AUDIT-06, issue #256 Group G): this entry previously described rcp_ep_gpio_apply_reconfig() as toggling a per-pin bitmask's flagged pins between RCP_REGMAP_PIN_PROP_OUTPUT and RCP_REGMAP_PIN_PROP_INPUT -- a mechanism this codebase's own file header had already, honestly, labelled its own invented design, and which corresponds to no TC18 register or mechanism at all (Table 44 (RC5), the real GPIO functional-configuration register block, has no per-pin direction field; direction lives in HW_config's own hw_pin_type, a different subsystem, configured only in HW_UNCONFIGURED state). That prior behavior is retained, under the honest name rcp_ep_gpio_toggle_pin_direction(), as a real but purely caller-side convenience no longer described as, or reachable from, evt[2:0]=111b. rcp_ep_gpio_apply_reconfig() now names TC18 §12.7.1 Figure 18's actual generic mechanism, common to every endpoint type: payload is a 16-bit big-endian relative start address into this endpoint's own EP_func block followed by configuration data octets, applied at octet granularity over the block rcp_ep_gpio_render_registers() renders, then adopted back into cfg, for a payload whose address and length fall within range. SPLIT 2026-08-18 (c-RCP-18-tracker, REQ-GPIO-* atomicity audit, issue #533): this entry's own prior text also bundled three further, independently-testable clauses -- the SHORT-payload rejection, the out-of-range-span rejection, and the read-only-octet-skip behavior -- each already independently tested in tests/test_ep_gpio.c but sharing this one id; they are now REQ-GPIO-040/-041/-042 respectively. This closes REQ-CFG-011/REQ-CFG-012's own gap for GPIO specifically (2 of 11 endpoint types now implement the mechanism; SPI/I2C/UART/LIN/CAN/ADC/ISELED/MDIO/wakeup remain open).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.7.1 Configuration of endpoints + Figure 19 (\"the data of the byte_msg_payload from a write request is written into the section of the EP that is addressed... any byte_msg_payload for which the length plus the start_address results in a value larger than the EP_LEN, is to be ignored\"), TC18.txt L2844-2862; §13.7.4.2 Table 44 (RC5) (gpio functional configuration register block), TC18.txt L4845-4880", + "tc18_master_id": "TC18-12.7.1-003" + }, + { + "id": "REQ-GPIO-014", + "title": "rcp_ep_gpio_trigger_fires() never fires for RCP_EP_GPIO_TRIGGER_NONE", + "text": "rcp_ep_gpio_trigger_fires() with trigger = RCP_EP_GPIO_TRIGGER_NONE shall return false for every combination of prev_level and new_level.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.1 (\"The GPIO endpoint generates triggers for all its mapped IO-pins on the change, falling and rising edge.\"), TC18.txt L4816", + "tc18_master_id": "TC18-13.7.4.1-011" + }, + { + "id": "REQ-GPIO-015", + "title": "rcp_ep_gpio_trigger_fires() implements RCP_EP_GPIO_TRIGGER_ANY_CHANGE", + "text": "rcp_ep_gpio_trigger_fires() with trigger = RCP_EP_GPIO_TRIGGER_ANY_CHANGE shall return true if and only if prev_level != new_level.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.1 Table 43 (RC5) (\"IO0 signal change\"), TC18.txt L4823", + "tc18_master_id": "TC18-13.7.4.1-012" + }, + { + "id": "REQ-GPIO-016", + "title": "rcp_ep_gpio_trigger_fires() implements RCP_EP_GPIO_TRIGGER_RISING", + "text": "rcp_ep_gpio_trigger_fires() with trigger = RCP_EP_GPIO_TRIGGER_RISING shall return true if and only if prev_level is false and new_level is true.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.1 Table 43 (RC5) (\"IO0 rising edge\"), TC18.txt L4824", + "tc18_master_id": "TC18-13.7.4.1-012" + }, + { + "id": "REQ-GPIO-017", + "title": "rcp_ep_gpio_trigger_fires() implements RCP_EP_GPIO_TRIGGER_FALLING", + "text": "rcp_ep_gpio_trigger_fires() with trigger = RCP_EP_GPIO_TRIGGER_FALLING shall return true if and only if prev_level is true and new_level is false.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.1 Table 43 (RC5) (\"IO0 falling edge\"), TC18.txt L4825", + "tc18_master_id": "TC18-13.7.4.1-012" + }, + { + "id": "REQ-GPIO-018", + "title": "rcp_ep_gpio_functional_cfg_init() zero-initializes cfg", + "text": "rcp_ep_gpio_functional_cfg_init() shall set cfg's common functional-config flags all false and every pins[i].pin_property to 0 and pins[i].trigger to RCP_EP_GPIO_TRIGGER_NONE.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-GPIO-019", + "title": "rcp_ep_gpio_functional_cfg_writable() is unwritable while HW_UNCONFIGURED", + "text": "rcp_ep_gpio_functional_cfg_writable() shall return false while state is RCP_LIFECYCLE_HW_UNCONFIGURED, for every writer context.", + "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-GPIO-020", + "title": "rcp_ep_gpio_functional_cfg_writable() requires an authorized writer while HW_CONFIGURED", + "text": "rcp_ep_gpio_functional_cfg_writable() shall return true while state is 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 \"for every writer context\", superseded by REQ-LIFECYCLE-030/036's authorization-gating fix (issue #198) -- the code and this module's own test (test_functional_cfg_writable_hw_configured_requires_authorization_or_discovery_stream, tests/test_ep_gpio.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-GPIO-021", + "title": "rcp_ep_gpio_functional_cfg_writable() requires authorization once RCP_CONFIGURED", + "text": "rcp_ep_gpio_functional_cfg_writable() shall, while state is RCP_LIFECYCLE_RCP_CONFIGURED, return true if and only if writer.via_root_client_ep0 or writer.via_owning_stream is true.", + "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-GPIO-022", + "title": "rcp_ep_gpio_set_pin_property() rejects an invalid pin index or an unauthorized write without mutating cfg", + "text": "rcp_ep_gpio_set_pin_property() shall return false and leave cfg unchanged when pin_index is not rcp_ep_gpio_pin_index_valid(), or when rcp_ep_gpio_functional_cfg_writable() denies the write for state/writer.", + "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-GPIO-021", + "tc18_master_id": "TC18-12.3.1.3-005" + }, + { + "id": "REQ-GPIO-023", + "title": "rcp_ep_gpio_set_pin_property() applies the write when authorized", + "text": "rcp_ep_gpio_set_pin_property() shall set cfg->pins[pin_index].pin_property to pin_property and return true when pin_index is valid and 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-GPIO-021", + "tc18_master_id": "TC18-12.3.1.3-005" + }, + { + "id": "REQ-GPIO-024", + "title": "rcp_ep_gpio_set_pin_trigger() rejects an invalid pin index or an unauthorized write without mutating cfg", + "text": "rcp_ep_gpio_set_pin_trigger() shall return false and leave cfg unchanged when pin_index is not rcp_ep_gpio_pin_index_valid(), or when rcp_ep_gpio_functional_cfg_writable() denies the write for state/writer.", + "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-GPIO-021", + "tc18_master_id": "TC18-12.3.1.3-005" + }, + { + "id": "REQ-GPIO-025", + "title": "rcp_ep_gpio_set_pin_trigger() applies the write when authorized", + "text": "rcp_ep_gpio_set_pin_trigger() shall set cfg->pins[pin_index].trigger to trigger and return true when pin_index is valid and 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-GPIO-021", + "tc18_master_id": "TC18-12.3.1.3-005" + }, + { + "id": "REQ-GPIO-026", + "title": "GPIO read request encode/decode round-trips", + "text": "rcp_ep_gpio_decode_read_request() shall, given a frame produced by rcp_ep_gpio_encode_read_request() with the same byte_bus_id, return RCP_EP_GPIO_OK and recover the original transaction_num.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.1 (\"A request not having exactly four bytes is rejected and an error response with error code = INVALID_PARAMETER will be sent.\"), TC18.txt L4799-4800; general ACF frame basis, §13.5 Table 33, TC18.txt L4069-4116", + "tc18_master_id": "TC18-13.7.4.1-005" + }, + { + "id": "REQ-GPIO-027", + "title": "rcp_ep_gpio_decode_read_request() rejects a malformed or misaddressed frame", + "text": "rcp_ep_gpio_decode_read_request() shall return RCP_EP_GPIO_ERR_SHORT_FRAME for a frame shorter than the ACF_ABB fixed header or its declared payload length, RCP_EP_GPIO_ERR_BAD_MSG_TYPE for a non-ACF_ABB frame, RCP_EP_GPIO_ERR_WRONG_BUS when byte_bus_id != expected_bus_id, and RCP_EP_GPIO_ERR_WRONG_OP when op is not RCP_ACF_OP_READ.", + "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-GPIO-028", + "title": "GPIO write request encode/decode round-trips, including evt[2:0]", + "text": "rcp_ep_gpio_decode_write_request() shall, given a frame produced by rcp_ep_gpio_encode_write_request() with the same byte_bus_id, return RCP_EP_GPIO_OK and recover the original bitmask, evt[2:0] masked to its low three bits, and transaction_num.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.1 (\"A request not having exactly four bytes is rejected and an error response with error code = INVALID_PARAMETER will be sent.\"), TC18.txt L4799-4800; evt[2:0] semantics per §13.5 Table 33 (GPIO/PWM_OUT row, evt[2:0]=000b-111b), TC18.txt L4093-4115", + "tc18_master_id": "TC18-13.7.4.1-005" + }, + { + "id": "REQ-GPIO-029", + "title": "rcp_ep_gpio_decode_write_request() rejects a malformed or misaddressed frame", + "text": "rcp_ep_gpio_decode_write_request() shall return RCP_EP_GPIO_ERR_SHORT_FRAME for a frame shorter than the ACF_ABB fixed header or its declared payload length, RCP_EP_GPIO_ERR_BAD_MSG_TYPE for a non-ACF_ABB frame, RCP_EP_GPIO_ERR_WRONG_BUS when byte_bus_id != expected_bus_id, RCP_EP_GPIO_ERR_WRONG_OP when op is not RCP_ACF_OP_WRITE, and RCP_EP_GPIO_ERR_BAD_PAYLOAD_LEN when the payload is not exactly RCP_EP_GPIO_PAYLOAD_LEN octets.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.1 (\"A request not having exactly four bytes is rejected and an error response with error code = INVALID_PARAMETER will be sent.\"), TC18.txt L4799-4800", + "tc18_master_id": "TC18-13.7.4.1-005" + }, + { + "id": "REQ-GPIO-030", + "title": "GPIO response encode/decode round-trips when untimed", + "text": "rcp_ep_gpio_decode_response() shall, given a frame produced by rcp_ep_gpio_encode_response() with timed = false and the same byte_bus_id, return RCP_EP_GPIO_OK, recover the original bitmask 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.4.1 (\"A request not having exactly four bytes is rejected...\"), TC18.txt L4799-4800; response payload format mirrors the request's byte_msg_payload bitmask, Figure 25 (RC5), TC18.txt L4801-4808", + "tc18_master_id": "TC18-13.7.4.1-006" + }, + { + "id": "REQ-GPIO-031", + "title": "GPIO response encode/decode round-trips when timed", + "text": "rcp_ep_gpio_decode_response() shall, given a frame produced by rcp_ep_gpio_encode_response() with timed = true, the same byte_bus_id, and a timestamp, return RCP_EP_GPIO_OK, recover the original bitmask 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.4.1 (\"A request not having exactly four bytes is rejected...\"), TC18.txt L4799-4800; response payload format mirrors the request's byte_msg_payload bitmask, Figure 25 (RC5), TC18.txt L4801-4808", + "tc18_master_id": "TC18-13.7.4.1-006" + }, + { + "id": "REQ-GPIO-032", + "title": "rcp_ep_gpio_decode_response() rejects a malformed or misaddressed frame", + "text": "rcp_ep_gpio_decode_response() shall return RCP_EP_GPIO_ERR_SHORT_FRAME for a frame too short for its applicable ACF fixed header, RCP_EP_GPIO_ERR_WRONG_BUS when byte_bus_id != expected_bus_id, and RCP_EP_GPIO_ERR_BAD_PAYLOAD_LEN when the payload is not exactly RCP_EP_GPIO_PAYLOAD_LEN octets.", + "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-GPIO-033", + "title": "rcp_ep_gpio_wire_error() maps a bad payload length to INVALID_PARAMETER", + "text": "IMPLEMENTED (2026-08-12, issue #201 Phase 5e): rcp_ep_gpio_decode_write_request() and rcp_ep_gpio_decode_request() reject any GPIO request whose byte_msg_payload is not exactly RCP_EP_GPIO_PAYLOAD_LEN (4) octets with RCP_EP_GPIO_ERR_BAD_PAYLOAD_LEN; rcp_ep_gpio_wire_error() maps that local code to the numbered wire code TC18 13.7.4.1 answers with, RCP_ERROR_INVALID_PARAMETER, for a caller building an Error Response frame (acf.h's rcp_acf_build_error_response()). CORRECTED 2026-08-18 (c-RCP-18-tracker, REQ-GPIO-* atomicity audit, issue #533): this entry previously also asserted the LSB-first bit-to-pin mapping for an endpoint supporting fewer than RCP_EP_GPIO_MAX_PINS (32) pins is conformant by construction -- true, but that claim is entirely owned by REQ-GPIO-003/REQ-GPIO-004's own rcp_ep_gpio_pin_mask()/_pin_get() contracts (this module's fixed bit-index n <-> pin IOn encoding never changes based on how many pins a real instance physically has), a near-duplicate restating those two ids' own already-tested behavior rather than a distinct testable claim of this entry's own -- removed here to avoid two ids describing the same behavior, the same REQ-RMAP-059/061 attribution hazard issue #533's own tracker calls out.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.1, TC18.txt L4788-4800" + }, + { + "id": "REQ-GPIO-034", + "title": "GPIO trigger signal numbering (Table 40)", + "text": "c-RCP implements the three GPIO trigger conditions (rcp_ep_gpio_trigger_fires() for change, rising and falling edges) and now also assigns them TC18 Table 40 (RC1)/Table 43 (RC5) trigger signal numbers via rcp_ep_gpio_trigger_signal_number(): signal 0 is the whole-endpoint 'GPIO EP request execution done' trigger (not modelled by this per-pin function) and, for each pin IOn, signal 3n+1/3n+2/3n+3 is ANY_CHANGE/RISING/FALLING, up to signal 96 for IO31 FALLING. A triggered request naming a Table 40/43 signal number can now be resolved against a (pin_index, trigger) pair by this library.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.1 Table 43 (RC5), TC18.txt L4816-4829", + "tc18_master_id": "TC18-13.7.4.1-012" + }, + { + "id": "REQ-GPIO-035", + "title": "GPIO functional-config registers: base clock, divider and per-pin debounce (Table 44)", + "text": "PARTIAL (updated 2026-08-13, tc18-gap backlog PR D, issue #336): rcp_ep_gpio_functional_cfg_t carries ep_status, clk_divider, and a 32-entry debounce[] array, wire-addressable via the real evt[2:0]=111b EP_func mechanism (TC18 Table 44). rcp_ep_gpio_debounce_state_t/rcp_ep_gpio_debounce_sample() (ep_gpio.h/ep_gpio.c) implement the filtering RULE those registers configure -- directly unit-tested (test_ep_gpio.c). DISPATCH-WIRING HALF CLOSED THIS BATCH: test_tc18_gaps_ep.c's own new gpio_dispatch_handler() (an rcp_mock_endpoint_handler_fn registered via the existing, unmodified rcp_mock_server_add_endpoint()) is a real caller that decodes a GPIO write request and calls rcp_ep_gpio_debounce_sample() on every one, proven end-to-end through mock.c's own real dispatch() path (test_gpio_dispatch_debounces_writes_before_reporting_settled_value(): three writes of the same raw value with n=3 settle -- and are reported via a subsequent read -- only on the third, checked after every single write, not just at the end). This is a test-fixture-level reference handler, not new public library API -- mock.c's own file header states it deliberately 'owns none of the per-endpoint wire semantics itself... a caller registers one handler per byte_bus_id', so building this INTO mock.c itself would have contradicted that stated architecture; a caller-supplied handler is exactly the documented mechanism. What remains genuinely open: gpio_base_clk (0x0004) is read-only and always renders 0 -- this module defines no real GPIO clock source, the same architecture-wide constant already established for REQ-ADC-033/every other endpoint type's own base_clk field -- so the periodic sampling CADENCE (gpio_base_clk/gpio_clk_divider-derived) that would drive repeated rcp_ep_gpio_debounce_sample() calls independently of requests remains a caller-owned timer this module never itself runs; this batch's own handler instead samples once per write, a reasonable stand-in but not the real periodic cadence TC18 describes. SPLIT 2026-08-18 (c-RCP-18-tracker, REQ-GPIO-* atomicity audit, issue #533): rcp_ep_gpio_debounce_state_init()'s own separate zero-initialization contract, previously bundled under this same entry via a shared req tag even though this entry's own text never actually described init()'s behavior, is now REQ-GPIO-044's own separate id.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18-gap", + "status": "partial", + "tc18": "§13.7.4.2 Table 44, TC18.txt L4845-4880", + "tc18_master_id": "TC18-13.7.4.2-001" + }, + { + "id": "REQ-GPIO-036", + "title": "GPIO response timing: immediate for a pure read, post-debounce otherwise", + "text": "IMPLEMENTED (2026-08-14): the genuine remaining gap the prior batch's own text found -- \"mock.c's own dispatch model is entirely synchronous... actually WAITING the configured debounce time and THEN producing a response... would need a genuinely new mechanism this batch does not add\" -- is now closed. New rcp_mock_server_stash_deferred_response()/_take_deferred_response() (mock.h): a caller-facing pair (not GPIO-specific -- mock.c continues to own none of the per-endpoint wire semantics itself, this section's own established file-header boundary) that gives a response a real place to wait once a caller has decided not to answer synchronously, until whatever condition it was genuinely waiting for is later met. Neither function tracks a timer, elapsed time, or an 'is it ready yet' concept of its own -- matching the same 'protocol library, not a scheduler' boundary every other caller-driven-clock primitive in this codebase already uses (e.g. rcp_mock_server_check_watchdog()'s own elapsed_since_last_kick_ms parameter); the caller decides when to stash and when to take. A handler (rcp_mock_endpoint_handler_fn) cannot call either function itself -- it has no srv of its own -- so both are meant to be called by whatever code drives dispatch() itself, alongside it, matching how test_tc18_gaps_ep.c's own new test_gpio_dispatch_deferred_write_response_is_retrievable_once_debounce_settles() uses them: the SAME three-write debounce sequence test_gpio_dispatch_debounces_writes_before_reporting_settled_value() already proved reachable, but on the settling (3rd) write, the TEST itself (not the handler) now stashes the response that write genuinely owes, and a later take_deferred_response() call retrieves it exactly once, carrying that write's own real transaction_num -- proving a genuine 'answer withheld now, delivered later' round trip through mock.c for the first time, not just a response permanently skipped. 2 mutations (the stash assignment itself, and the take-side clear-after-taking step), both caught cleanly. This closes REQ-GPIO-036's own remaining gap only -- REQ-GPIO-035's own separate, still-open concern (gpio_base_clk always renders 0, no real periodic sampling cadence) is untouched by this fix and stays partial on its own terms, the same 'no real clock source' architecture-wide disposition already accepted for REQ-ADC-033 and every other endpoint type's own base_clk field.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.3, TC18.txt L4884-4894" + }, + { + "id": "REQ-GPIO-037", + "title": "A write to a pin configured as input leaves that pin's value unchanged", + "text": "rcp_ep_gpio_apply_masked_write() shall, for every evt, commit rcp_ep_gpio_apply_write()'s combined result to a bit position only when pins[i] has RCP_REGMAP_PIN_PROP_OUTPUT set, and shall leave that bit position's value from current unchanged when pins[i] does not, regardless of what request or the combinator's result specify for that position.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.3 (\"A write request to an input pin is ignored for this input pin\"), TC18.txt L4890", + "tc18_master_id": "TC18-13.7.4.3-004" + }, + { + "id": "REQ-GPIO-038", + "title": "rcp_ep_gpio_render_registers() serializes the GPIO EP_func block exactly as apply_reconfig() would read it back", + "text": "ADDED 2026-08-11 (c-RCP-AUDIT-06, issue #256 Group G, REQ-GPIO-013): rcp_ep_gpio_render_registers() shall serialize cfg's EP_func registers into out[0..RCP_EP_GPIO_EP_FUNC_LEN) at the TC18 Table 44 (RC5) offsets (gpio_ep_len=0x0000 reporting RCP_EP_GPIO_EP_FUNC_LEN itself; gpio_io_max=0x0001 reporting RCP_EP_GPIO_MAX_PINS; gpio_ep_enable&clr=0x0002/gpio_ep_options=0x0003 packed from regmap.h's shared common-entries flags; gpio_base_clk=0x0004 always 0; gpio_ep_status=0x0006; gpio_clk_divider=0x0008; gpio_debounce_IO0..IO31=0x0009..0x0028), matching the exact image rcp_ep_gpio_apply_reconfig() patches in place and parses back. SPLIT 2026-08-18 (c-RCP-18-tracker, REQ-GPIO-* atomicity audit, issue #533): rcp_ep_gpio_encode_reconfig_request()'s own separate wire-encoding contract, previously bundled into this same entry as a second, unrelated function's behavior, is now REQ-GPIO-043's own separate id.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.2 Table 44 (RC5), TC18.txt L4845-4880; §12.7.1 Figure 19 (RC5), TC18.txt L2848-2856", + "tc18_master_id": "TC18-13.7.4.2-001" + }, + { + "id": "REQ-GPIO-039", + "title": "rcp_ep_gpio_reconfig_strerror() returns a distinct, non-NULL message per rcp_ep_gpio_reconfig_errc_t value", + "text": "ADDED 2026-08-11 (c-RCP-AUDIT-06, issue #256 Group G, REQ-GPIO-013): rcp_ep_gpio_reconfig_strerror() shall return a distinct, non-NULL, human-readable message for each of RCP_EP_GPIO_RECONFIG_OK, RCP_EP_GPIO_RECONFIG_ERR_SHORT, and RCP_EP_GPIO_RECONFIG_ERR_OUT_OF_RANGE, and a non-NULL message for any other (invalid) value -- matching ep_pwm.h's own rcp_ep_pwm_out_reconfig_strerror() precedent exactly.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.2 Table 44 (RC5), TC18.txt L4845-4880", + "tc18_master_id": "TC18-13.7.4.2-001" + }, + { + "id": "REQ-GPIO-040", + "title": "rcp_ep_gpio_apply_reconfig() rejects a payload with no address+data", + "text": "rcp_ep_gpio_apply_reconfig() shall return RCP_EP_GPIO_RECONFIG_ERR_SHORT and leave cfg entirely unchanged when payload_len is not at least RCP_EP_GPIO_RECONFIG_ADDR_LEN + 1. Split 2026-08-18 (c-RCP-18-tracker, REQ-GPIO-* atomicity audit, issue #533) out of REQ-GPIO-013, whose own text previously bundled this rejection clause with the core addressed-write mechanism and two other independently-testable clauses under one id -- see that entry's own text for the split rationale and the core mechanism.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.7.1 Figure 19 (\"any byte_msg_payload for which the length plus the start_address results in a value larger than the EP_LEN, is to be ignored\"), TC18.txt L2844-2862", + "tc18_master_id": "TC18-12.7.1-003" + }, + { + "id": "REQ-GPIO-041", + "title": "rcp_ep_gpio_apply_reconfig() rejects a write whose span exceeds the EP_func block", + "text": "rcp_ep_gpio_apply_reconfig() shall return RCP_EP_GPIO_RECONFIG_ERR_OUT_OF_RANGE and leave cfg entirely unchanged when the addressed span (start_address + data_len) would extend past RCP_EP_GPIO_EP_FUNC_LEN, per the specification's own \"such a payload is to be ignored\" rule. Split 2026-08-18 (c-RCP-18-tracker, REQ-GPIO-* atomicity audit, issue #533) out of REQ-GPIO-013, whose own text previously bundled this rejection clause with the core addressed-write mechanism and two other independently-testable clauses under one id -- see that entry's own text for the split rationale and the core mechanism.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.7.1 Figure 19 (\"any byte_msg_payload for which the length plus the start_address results in a value larger than the EP_LEN, is to be ignored\"), TC18.txt L2844-2862", + "tc18_master_id": "TC18-12.7.1-003" + }, + { + "id": "REQ-GPIO-042", + "title": "rcp_ep_gpio_apply_reconfig() leaves read-only registers unchanged within an otherwise-applied span", + "text": "rcp_ep_gpio_apply_reconfig() shall leave any octet of a valid addressed span that lands on a read-only register (EP_LEN, IO_MAX, base_clk) at its current value, while still applying the remaining octets of that same span. Split 2026-08-18 (c-RCP-18-tracker, REQ-GPIO-* atomicity audit, issue #533) out of REQ-GPIO-013, whose own text previously bundled this read-only-skip clause with the core addressed-write mechanism and two other independently-testable clauses under one id -- see that entry's own text for the split rationale and the core mechanism.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.4.2 Table 44 (RC5) (gpio functional configuration register block), TC18.txt L4845-4880", + "tc18_master_id": "TC18-13.7.4.2-001" + }, + { + "id": "REQ-GPIO-043", + "title": "rcp_ep_gpio_encode_reconfig_request() encodes an addressed configuration write", + "text": "rcp_ep_gpio_encode_reconfig_request() shall encode an ACF_ABB write request (evt[2:0] = RCP_EP_GPIO_WRITE_RECONFIG) whose payload is start_address (16-bit big-endian) followed by data[0..data_len), and shall return a zeroed rcp_bytes_t when data_len is 0, data is NULL, the encoded payload would exceed RCP_ACF_MAX_PAYLOAD, or on allocation failure. Split 2026-08-18 (c-RCP-18-tracker, REQ-GPIO-* atomicity audit, issue #533) out of REQ-GPIO-038, whose own text previously bundled this function's contract with rcp_ep_gpio_render_registers()'s own, unrelated, serialization contract under one id -- see that entry's own text for the render side.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.7.1 Figure 19 (RC5), TC18.txt L2848-2856", + "tc18_master_id": "TC18-12.7.1-003" + }, + { + "id": "REQ-GPIO-044", + "title": "rcp_ep_gpio_debounce_state_init() zero-initializes a debounce state", + "text": "rcp_ep_gpio_debounce_state_init() shall zero-initialize s, leaving has_settled and has_candidate both false. Split 2026-08-18 (c-RCP-18-tracker, REQ-GPIO-* atomicity audit, issue #533) out of REQ-GPIO-035, which previously carried this function's own req tag without describing its behavior in text at all -- see that entry's own text for the debounce-filtering rule this function's callers rely on afterward.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18-gap", + "status": "implemented", + "tc18": "§13.7.4.2 Table 44, TC18.txt L4845-4880", + "tc18_master_id": "TC18-13.7.4.2-001" + }, + { + "id": "REQ-GPIO-045", + "title": "rcp_ep_gpio_decode_write_request() rejects the reserved evt[2:0]=100b value", + "text": "rcp_ep_gpio_decode_write_request() shall return RCP_EP_GPIO_ERR_RESERVED_EVT, without populating any output parameter, when the decoded evt[2:0] equals RCP_EP_GPIO_WRITE_RESERVED4. Split 2026-08-18 (c-RCP-18-tracker, REQ-GPIO-* atomicity audit, issue #533) out of REQ-GPIO-012, whose own text previously bundled this decode-time detection with rcp_ep_gpio_apply_write()'s own no-op contract and rcp_ep_gpio_wire_error()'s own mapping contract, three different functions under one id -- see that entry's own text for the apply_write() no-op half and REQ-GPIO-046 for the wire_error() mapping half.", + "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" + }, + { + "id": "REQ-GPIO-046", + "title": "rcp_ep_gpio_wire_error() maps the reserved-evt error to UNSUPPORTED_CMD", + "text": "rcp_ep_gpio_wire_error() shall return RCP_ERROR_UNSUPPORTED_CMD for RCP_EP_GPIO_ERR_RESERVED_EVT. Split 2026-08-18 (c-RCP-18-tracker, REQ-GPIO-* atomicity audit, issue #533) out of REQ-GPIO-012, whose own text previously bundled this wire-error-mapping contract with rcp_ep_gpio_apply_write()'s own no-op contract and rcp_ep_gpio_decode_write_request()'s own detection contract, three different functions under one id -- see that entry's own text for the apply_write() no-op half and REQ-GPIO-045 for the decode-time detection half.", + "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" + }, + { + "id": "REQ-ADC-010", + "title": "rcp_ep_adc_collect_response_values() returns 0 when either count is 0", + "text": "rcp_ep_adc_collect_response_values() shall return 0 and write nothing when avg_count == 0 or value_count == 0.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.3 (\"Responses contain as much measurement values as requested by half the read size of a request.\"), TC18.txt L5162-5163", + "tc18_master_id": "TC18-13.7.9.3-002" + }, + { + "id": "REQ-ADC-011", + "title": "rcp_ep_adc_encode_response() carries value_count measurement values and reports 2 * value_count as read_size", + "text": "rcp_ep_adc_encode_response() shall encode values[0..value_count) as a value_count * RCP_EP_ADC_VALUE_LEN octet big-endian payload with the header's read_size set to that payload length. SPLIT 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch): this id previously also bundled the zeroed-rcp_bytes_t failure case for value_count == 0 or > RCP_EP_ADC_MAX_VALUES; that is now REQ-ADC-042, its own independently-tested behaviour (test_response_encode_rejects_zero_or_oversized_value_count). This split also corrects a pre-existing tag-placement bug: this id's //cfusa:req tag was misplaced above rcp_ep_adc_collect_response_values() -- an unrelated function -- rather than above rcp_ep_adc_encode_response(), the function its own text has always actually described; moved to the correct function. The REQ-ADC-027/028/030 tags that were also erroneously duplicated onto rcp_ep_adc_encode_response() (those ids belong to rcp_ep_adc_decode_response(), which already carried them correctly on its own) have been removed from it.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.3 (\"Responses contain as much measurement values as requested by half the read size of a request.\"), TC18.txt L5162-5163", + "tc18_master_id": "TC18-13.7.9.3-002" + }, + { + "id": "REQ-ADC-012", + "title": "rcp_ep_adc_capture_moment_timestamp() returns the first response value's timestamp", + "text": "rcp_ep_adc_capture_moment_timestamp() shall return avg_values[0].timestamp for any avg_count > 0 -- the moment the last sample feeding the response's first measurement value was captured.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.3 (\"If the response includes a timestamp, it shall represent the point in time when the last sample that was used for the first average value that is included in the response has been captured.\"), TC18.txt L5143-5145", + "tc18_master_id": "TC18-13.7.9.2-006" + }, + { + "id": "REQ-ADC-013", + "title": "rcp_ep_adc_capture_moment_timestamp() returns 0 when avg_count is 0", + "text": "rcp_ep_adc_capture_moment_timestamp() shall return 0 when avg_count == 0.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.3 (\"If the response includes a timestamp, it shall represent the point in time when the last sample...\"), TC18.txt L5143-5145", + "tc18_master_id": "TC18-13.7.9.2-006" + }, + { + "id": "REQ-ADC-014", + "title": "rcp_ep_adc_functional_cfg_init() zero-initializes cfg", + "text": "rcp_ep_adc_functional_cfg_init() shall set every common flag false and adc_samples_per_avg_interval, adc_avg_intervals_per_request and adc_combine_avg_values all to 0, regardless of cfg's prior contents.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-ADC-015", + "title": "rcp_ep_adc_functional_cfg_writable() is unwritable while HW_UNCONFIGURED", + "text": "rcp_ep_adc_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 L2177-2178", + "tc18_master_id": "TC18-12.3.1.2-001" + }, + { + "id": "REQ-ADC-016", + "title": "rcp_ep_adc_functional_cfg_writable() requires authorization or a discovery stream once HW_CONFIGURED", + "text": "rcp_ep_adc_functional_cfg_writable() shall return false for state == RCP_LIFECYCLE_HW_CONFIGURED when writer indicates none of via_root_client_ep0, via_owning_stream, or via_discovery_stream, and true when any of them is set (REQ-LIFECYCLE-030/036 superseded the earlier 'writable by any writer' rule).", + "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 L2177-2178 -- writable once concluded (i.e. HW_CONFIGURED)", + "tc18_master_id": "TC18-12.3.1.2-004" + }, + { + "id": "REQ-ADC-017", + "title": "rcp_ep_adc_functional_cfg_writable() requires authorization once RCP_CONFIGURED", + "text": "rcp_ep_adc_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 L2203-2206, L2225-2226", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-ADC-018", + "title": "rcp_ep_adc_set_samples_per_avg_interval() rejects an unauthorized write without mutating cfg", + "text": "rcp_ep_adc_set_samples_per_avg_interval() shall return false and leave cfg unchanged when the write is not authorized by rcp_ep_adc_functional_cfg_writable().", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.3, TC18.txt L2225-2226 (W* marker convention) -- same authorization basis as REQ-ADC-019 (corrected 2026-08-11, c-RCP-AUDIT-06, issue #256 Group J: this entry previously cited §13.7.9.1's own averaging-interval prose, TC18.txt L5040/L5107 -- background on why this field is writable at all, not the authorization-rejection behavior this requirement actually describes; REQ-ADC-019's own citation already correctly names this entry as sharing its W*-marker basis, so this entry's citation was the one out of step)", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-ADC-019", + "title": "rcp_ep_adc_set_samples_per_avg_interval() applies the write when authorized", + "text": "rcp_ep_adc_set_samples_per_avg_interval() shall return true and set cfg->adc_samples_per_avg_interval 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 L2225-2226 (W* marker convention) -- same authorization basis as REQ-ADC-018", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-ADC-020", + "title": "rcp_ep_adc_set_avg_intervals_per_request() rejects an unauthorized write without mutating cfg", + "text": "rcp_ep_adc_set_avg_intervals_per_request() shall return false and leave cfg unchanged when the write is not authorized by rcp_ep_adc_functional_cfg_writable().", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.2 Table 54 (\"adc_avg_intervals_per_request ... Intervals to be captures per measurement cycle\"), TC18.txt L5102-5103; §12.3.1.3, TC18.txt L2225-2226 (W* marker convention)", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-ADC-021", + "title": "rcp_ep_adc_set_avg_intervals_per_request() applies the write when authorized", + "text": "rcp_ep_adc_set_avg_intervals_per_request() shall return true and set cfg->adc_avg_intervals_per_request 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 L2225-2226 (W* marker convention) -- same authorization basis as REQ-ADC-018", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-ADC-022", + "title": "rcp_ep_adc_set_combine_avg_values() rejects an unauthorized write without mutating cfg", + "text": "rcp_ep_adc_set_combine_avg_values() shall return false and leave cfg unchanged when the write is not authorized by rcp_ep_adc_functional_cfg_writable().", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.2 Table 54 (\"adc_combine_avg_values ... Nr of output values to be combined in one response\"), TC18.txt L5110-5111; §12.3.1.3, TC18.txt L2225-2226 (W* marker convention)", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-ADC-023", + "title": "rcp_ep_adc_set_combine_avg_values() applies the write when authorized", + "text": "rcp_ep_adc_set_combine_avg_values() shall return true and set cfg->adc_combine_avg_values to the requested output-value count when the write is authorized; every value the one-octet field can hold is a legal count.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.3.1.3, TC18.txt L2225-2226 (W* marker convention) -- same authorization basis as REQ-ADC-018", + "tc18_master_id": "TC18-12.3.1.3-001" + }, + { + "id": "REQ-ADC-024", + "title": "rcp_ep_adc_strerror() never returns NULL and is unique per code", + "text": "rcp_ep_adc_strerror() shall return a non-NULL, non-empty, distinct message for each rcp_ep_adc_errc_t value, including an out-of-range value.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-ADC-025", + "title": "ADC read request encode/decode round-trips, carrying read_size", + "text": "rcp_ep_adc_decode_read_request() shall, given a frame produced by rcp_ep_adc_encode_read_request() with the same byte_bus_id, return RCP_EP_ADC_OK and recover the original read_size and transaction_num. SPLIT 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch): this id previously also bundled 'the request itself shall carry no payload' as a separate, previously-untested clause about rcp_ep_adc_encode_read_request()'s own wire output; that is now REQ-ADC-043, closing a real silent-gap risk of exactly the kind issue #519's own REQ-DL-001 finding warned about -- no existing test asserted the encoded frame carries a zero-length payload before this split's new test_read_request_carries_no_payload().", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.3 (\"The ADC request has no byte_msg_payload...\"), TC18.txt L5162", + "tc18_master_id": "TC18-13.7.9.3-001" + }, + { + "id": "REQ-ADC-026", + "title": "rcp_ep_adc_decode_read_request() rejects a frame shorter than the ACF_ABB fixed header", + "text": "rcp_ep_adc_decode_read_request() shall return RCP_EP_ADC_ERR_SHORT_FRAME for a frame shorter than the ACF_ABB fixed header. SPLIT 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch): this id previously bundled four distinct decode_read_request() error-path behaviours under one id (SHORT_FRAME / WRONG_BUS / WRONG_OP / BAD_EVT), each already independently tested (test_read_request_rejects_short_frame / _wrong_bus / _wrong_op / _nonzero_evt) -- confirming the bundling. WRONG_BUS is now REQ-ADC-044, WRONG_OP is REQ-ADC-045, BAD_EVT is REQ-ADC-046. A fifth clause describing dispatch-layer behaviour ('every other value shall be rejected with error code UNSUPPORTED_CMD at the dispatch layer') is deliberately NOT re-split into its own id: no rcp_ep_adc_wire_error() mapping function exists in ep_adc.c (contrast ep_gpio.c's/ep_pwm.c's own, issue #426) and no dispatch-layer code anywhere in this codebase maps RCP_EP_ADC_ERR_BAD_EVT to RCP_ERROR_UNSUPPORTED_CMD for ADC specifically -- minting a requirement id for it would violate this audit's own rule that each split id needs a real, distinct test, and there is nothing here to test. This is a genuine, pre-existing implementation gap (RCP_EP_ADC_ERR_BAD_EVT's own header comment already documents the caller as responsible for that mapping, but no caller in this codebase performs it for ADC), left honestly recorded rather than given a fabricated passing test; implementing it is out of scope for an atomicity-only audit.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L3666-3710", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-ADC-027", + "title": "ADC response encode/decode round-trips every measurement value when untimed", + "text": "rcp_ep_adc_decode_response() shall, given a frame produced by rcp_ep_adc_encode_response() with timed = false and the same byte_bus_id, return RCP_EP_ADC_OK, recover all value_count values in order plus the original 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.9.3 (\"Responses contain as much measurement values as requested by half the read size of a request.\" / Figure 32, \"Response with a single measurement value\"), TC18.txt L5162-5167", + "tc18_master_id": "TC18-13.7.9.3-002" + }, + { + "id": "REQ-ADC-028", + "title": "ADC response encode/decode round-trips every measurement value when timed", + "text": "rcp_ep_adc_decode_response() shall, given a frame produced by rcp_ep_adc_encode_response() with timed = true, the same byte_bus_id, and a timestamp, return RCP_EP_ADC_OK, recover all value_count values in order plus the original 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.9.3 (\"Responses contain as much measurement values as requested by half the read size of a request.\" / Figure 32), TC18.txt L5162-5167", + "tc18_master_id": "TC18-13.7.9.3-002" + }, + { + "id": "REQ-ADC-029", + "title": "rcp_ep_adc_decode_response() rejects a bad-payload-length frame", + "text": "rcp_ep_adc_decode_response() shall return RCP_EP_ADC_ERR_BAD_PAYLOAD_LEN when the decoded payload is empty or is not a whole number of RCP_EP_ADC_VALUE_LEN-octet values. SPLIT 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch): this id previously also bundled the ERR_TOO_MANY_VALUES clause under one id despite only a single 'shall' occurrence in its own text -- the exact 'shall'-count-proxy blind spot issue #519 warned about, mirroring the REQ-RMAP-059/061 zero-'shall' pattern. That clause is now REQ-ADC-047, its own independently-tested behaviour (test_response_decode_rejects_more_values_than_caller_can_hold, which already existed as its own separate test function before this split, distinct from test_response_decode_rejects_bad_payload_len).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33 (ADC/PWM_IN/I²C/LIN/CAN/UART/ISELED/MDIO row), TC18.txt L3684-3693", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-ADC-030", + "title": "ADC response encode/decode round-trips RCP_EP_PWM_IN_NO_SIGNAL verbatim in its own value slot", + "text": "rcp_ep_adc_decode_response() shall, given a frame produced by rcp_ep_adc_encode_response() where some values[i] == RCP_EP_PWM_IN_NO_SIGNAL, recover that sentinel unchanged in out_values[i]. RESOLVED (issue #184, c-RCP-AUDIT-05), left honestly uncited rather than force-cited: same basis as REQ-PWM-047's own resolution note -- TC18 defines no payload-sentinel convention for ADC or PWM_IN, only the numbered §12.9.6 Table 30 error-response code (PWM_IN_NO_SIGNAL, value 9), which this wire-level round-trip does not use or displace.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-ADC-031", + "title": "rcp_ep_adc_trigger_state_init() starts with no previous value tracked", + "text": "rcp_ep_adc_trigger_state_init() shall initialize an rcp_ep_adc_trigger_state_t with has_previous == false, so the first rcp_ep_adc_trigger_evaluate() call on it cannot fire any edge-triggered signal. SPLIT 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch): this id previously bundled rcp_ep_adc_trigger_state_init()'s own contract together with all five of rcp_ep_adc_trigger_evaluate()'s independent TC18 §13.7.9.1 Table 53 trigger-output behaviours under one id -- exactly the 'one switch/if arm, one outcome' bundling pattern CONTRIBUTING.md's convention calls out, mirroring this codebase's own REQ-PWM-002..009 precedent for splitting one function's independently-firing outcomes into separate ids. The five trigger outputs are now REQ-ADC-048 (BELOW_MIN), REQ-ADC-049 (ABOVE_MIN), REQ-ADC-050 (BELOW_MAX), REQ-ADC-051 (ABOVE_MAX), and REQ-ADC-052 (MEASUREMENT_FINISHED); this id keeps only rcp_ep_adc_trigger_state_init()'s own, separate, already-distinctly-tested contract (test_trigger_state_init_has_no_previous_value). Originally IMPLEMENTED, FIXED 2026-08-12 (issue #201 batch) as a single combined entry; see REQ-ADC-048 through REQ-ADC-052 for that batch's remaining implementation and mutation-testing history.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.1 Table 53, TC18.txt L5052-5058", + "tc18_master_id": "TC18-13.7.9.1-009" + }, + { + "id": "REQ-ADC-032", + "title": "An ADC endpoint serves exactly one channel, is limited to 16-bit resolution, and requires a selected analog input pin", + "text": "c-RCP fixes an ADC measurement value at 16 bits (RCP_EP_ADC_VALUE_LEN == 2, ep_adc.h) consistent with TC18 §13.7.9.1's 16-bit ceiling. The catalogued claim that regmap.h's rcp_regmap_named_signal_t index has no ADC entry is stale: RCP_REGMAP_SIGNAL_ADC_IN (REQ-RMAP-044) has existed since an earlier batch, and rcp_regmap_named_signal_ep_signal_nr(RCP_REGMAP_SIGNAL_ADC_IN) returns 0, its own Table 23 EP_Signal_Nr -- an ADC endpoint's analog input CAN already be bound to a hardware pin via an ordinary hw_pin_map entry (hw_ep_nr = the ADC endpoint's own number, hw_ep_pin_nr = 0), the same generic, endpoint-type-agnostic mechanism every other endpoint type already uses; no ADC-specific binding code was ever needed. The one-channel-per-endpoint rule is structurally guaranteed by the wire format itself, not something this library needs to separately validate: Table 23 enumerates exactly one ADC-relevant signal (ADC_IN, EP_Signal_Nr 0), so hw_ep_pin_nr for an ADC endpoint's binding can only ever be 0 -- there is no second ADC channel number the addressing scheme could even express. Whether a given ADC endpoint's own hw_pin_map row is actually populated by a real deployment's configuration is a caller/config-time concern, the same as every other endpoint type's own pin binding -- not a decode/encode gap in this library.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.1, TC18.txt L5027-5030", + "tc18_master_id": "TC18-13.7.9.1-001" + }, + { + "id": "REQ-ADC-033", + "title": "ADC inter-sample spacing is one adc_sample_interval, in multiples of adc_base_clk x adc_base_clk_divider", + "text": "PARTIAL (catalogued field claim corrected): TC18 §13.7.9.1 requires that when adc_avg_intervals_per_request x adc_samples_per_avg_interval exceeds 1, successive samples be taken one adc_sample_interval apart, where that interval is expressed in multiples of adc_base_clk scaled by adc_base_clk_divider. The earlier claim that rcp_ep_adc_functional_cfg_t carries neither adc_sample_interval nor adc_base_clk_divider is stale: both exist as real config fields (sample_interval/base_clk_divider), wired to Table 54's own register block since an earlier batch (REQ-ADC-035/036). What remains genuinely unimplemented, and for a documented reason rather than an oversight: adc_base_clk itself is deliberately NOT modelled as a real value (rcp_ep_adc_render_registers() always renders it 0, the same 'no real clock source' honesty ep_gpio.h's/ep_i2c.h's/ep_lin.h's own base_clk fields already commit to) -- so this module has no way to convert adc_sample_interval (a count of ADC_CLK cycles) into actual wall-clock spacing, and rcp_ep_adc_average_interval() still consumes caller-supplied samples without validating their real-time spacing. Enforcing the temporal geometry would mean inventing a clock model this codebase deliberately doesn't have for any endpoint type, not a routine field-wiring fix. CLOSED 2026-08-14: rcp_ep_adc_validate_sample_spacing() (ep_adc.h/ep_adc.c) is the real, testable spacing check this entry's own text said was missing -- without inventing the clock model adc_base_clk itself still deliberately does not carry (unchanged; still always renders 0). Instead, base_clk_hz is a NEW parameter this function requires the caller to supply directly -- the caller's own real oscillator frequency in Hz, the same 'this library never invents wall time or a clock rate itself' discipline REQ-TIMED-012's own caller-supplied gptp_reference_now parameter already established for presentation-time admission. Computes expected_spacing_ns = sample_interval * base_clk_divider * 1e9 / base_clk_hz (TC18's own ADC_CLK-cycles-to-nanoseconds conversion) and validates every consecutive pair of samples[]'s own real wall-clock timestamp field against it, within a caller-chosen tolerance_ns; a non-monotonic timestamp pair is its own distinct violation, caught before the subtraction that would otherwise underflow. Fails open (no real information to check against) when sample_count < 2, base_clk_hz == 0, or base_clk_divider == 0 -- never asserts a false violation from a degenerate or absent clock configuration. The old deviation-pin test's own 'even' vs. 'ragged' sample fixtures are now genuinely distinguished by this new primitive (previously indistinguishable at rcp_ep_adc_average_interval()'s own output, which has no timing awareness of its own and still does not -- that remains correct, unchanged behavior for that function specifically, now pinned by its own dedicated test). The tolerance-window and non-monotonicity-guard logic were both mutation-tested and caught cleanly, including a wide-tolerance edge case that would otherwise let an underflowed non-monotonic pair slip through as a false OK.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.1, TC18.txt L5036-5039", + "tc18_master_id": "TC18-13.7.9.1-005" + }, + { + "id": "REQ-ADC-034", + "title": "ADC sampling occurs only while a request executes, and a compound wait compares the last acquired average without sampling", + "text": "IMPLEMENTED (2026-08-13, catalog-drift correction, issue #336): this requirement's own \"NOT IMPLEMENTED\" text was stale on two independent counts. (1) Its own precedent citation -- \"contrast ep_lin.h's rcp_ep_lin_compare_fires(), REQ-LINEP-002..005\" -- names a function and requirement ids that do not exist anywhere in this codebase (REQ-LINEP-002 through 005 were never filed; the lowest LINEP id in the catalog is 006); the real, existing mechanism is acf.h's rcp_acf_compound_wait_match(), a universal, endpoint-agnostic comparator wired into real dispatch via server.c's rcp_server_tick_ctx_t.current_status -- exactly the same mechanism REQ-UART-035 (issue #201) already corrected an identical stale claim for. \"Comparing against the last acquired average\" is simply whatever the caller supplies as current_status; no ADC-specific comparator was ever needed, the same as none was needed for UART. tests/test_acf.c already carries 45+ dedicated assertions for this shared mechanism. (2) The other half of this requirement -- sampling only while a request executes, so no trigger fires absent a request -- is genuinely out of scope by this module's own documented design, not a gap: ep_adc.h's file header states plainly that \"this module never itself owns a timer, thread, or background sampling loop\", so there is no c-RCP-owned sampling loop for any caller-side gating rule to apply to (the same scope boundary already established for REQ-ADC-037's cadence scheduling and every other endpoint type's own hardware-adjacent boundary). rcp_ep_adc_trigger_evaluate() (REQ-ADC-031, issue #201) already gives the caller the trigger-firing decision itself; whether the caller invokes it only during request execution is the caller's own orchestration, matching this module's consistent \"pure functions over caller-supplied state\" architecture throughout. Renamed the stale deviation-pin test in tests/test_tc18_gaps_ep2.c (test_adc_has_no_trigger_outputs_and_no_retained_average -> test_adc_pipeline_is_stateless_by_design_and_cadence_deviation_pin) and rewrote both its comment blocks -- the first also corrected a second, independent staleness (REQ-ADC-031 already implemented Table 53's trigger outputs; the old comment predated it).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.1, TC18.txt L5060-5063", + "tc18_master_id": "TC18-13.7.9.1-011" + }, + { + "id": "REQ-ADC-035", + "title": "adc_ep_len, adc_base_clk, adc_ep_status and adc_base_clk_divider register rows of Table 54 are now modeled", + "text": "FIXED 2026-08-11 (c-RCP-AUDIT-06, issue #256 Group I): c-RCP now models the ADC functional-configuration block's descriptor, clock and status registers (TC18 §13.7.9.2 Table 54) via rcp_ep_adc_render_registers()/_apply_reconfig() (REQ-ADC-038/039): adc_ep_len (0x0000, 8 bit, R), the reserved octet at 0x0001 (8 bit, R), adc_base_clk (0x0004, 16 bit, R — not itself stored, always renders 0, the same 'no real clock source modelled' honesty ep_gpio.h's/ep_i2c.h's/ep_lin.h's own base_clk fields already commit to), adc_ep_status (0x0006, 16 bit, R/W, new field), and adc_base_clk_divider (0x0008, 8 bit, R/W, new field). Unlike SPI's/UART's/LIN's own diverging fields, rcp_ep_adc_functional_cfg_t's pre-existing adc_samples_per_avg_interval/adc_avg_intervals_per_request/adc_combine_avg_values fields share Table 54's own register names exactly and are reused directly by the register block (with an honestly-documented 8-bit truncation on render for the two wider uint16_t fields, since their setters apply no range check).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.2 Table 54, TC18.txt L5085-5098", + "tc18_master_id": "TC18-13.7.9.2-001" + }, + { + "id": "REQ-ADC-036", + "title": "adc_sample_interval, the ADC_CLK cycle count between two samples, is now modeled", + "text": "FIXED 2026-08-11 (c-RCP-AUDIT-06, issue #256 Group I): c-RCP now models adc_sample_interval (TC18 §13.7.9.2 Table 54, relative address 0x0009, 8 bit, R/W) — the number of ADC_CLK cycles the endpoint shall wait between two consecutive samples — as rcp_ep_adc_functional_cfg_t.sample_interval, reachable via the register block (REQ-ADC-038/039). There is still no dedicated rcp_ep_adc_set_sample_interval() named setter (matching every other endpoint type's own precedent: a register-block-only field has no dedicated named setter, only the generic §12.7.1 write path reaches it), but the sample spacing §13.7.9.1's worked examples set to 1 us is now configurable over the wire.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.2 Table 54, TC18.txt L5100-5101", + "tc18_master_id": "TC18-13.7.9.2-001" + }, + { + "id": "REQ-ADC-037", + "title": "rcp_ep_adc_cadence_case() classifies the ACCUMULATE/FAN_OUT/ONE_TO_ONE relationship between adc_combine_avg_values and adc_avg_intervals_per_request", + "text": "rcp_ep_adc_cadence_case() shall classify which of TC18 §13.7.9.2's three cadence cases applies by comparing adc_combine_avg_values against adc_avg_intervals_per_request: RCP_EP_ADC_CADENCE_ACCUMULATE when combine > intervals, RCP_EP_ADC_CADENCE_FAN_OUT when combine < intervals, and RCP_EP_ADC_CADENCE_ONE_TO_ONE when they are equal. SPLIT 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch): this id previously also bundled rcp_ep_adc_cadence_response_ready()'s own, separate readiness-comparison contract -- a different function entirely, already independently tested -- under the same id; that is now REQ-ADC-053, which also retains this entry's prior dispatch-wiring PARTIAL narrative (that narrative describes cadence_response_ready()'s own real-dispatch integration, not cadence_case()'s). Directly unit-tested (test_cadence_case_accumulate_when_combine_exceeds_intervals, test_cadence_case_one_to_one_when_combine_equals_intervals, test_cadence_case_fan_out_when_combine_below_intervals, test_cadence_case_boundary_values), including both boundary conditions -- this id's own function has no partial or unimplemented caveat.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.2 (\"When adc_combine_avg_values > adc_avg_intervals_per_request... When adc_combine_avg_values = adc_avg_intervals_per_request... When adc_combine_avg_values < adc_avg_intervals_per_request...\"), TC18.txt L5128-5133" + }, + { + "id": "REQ-ADC-038", + "title": "rcp_ep_adc_render_registers() serializes the ADC functional-configuration block per Table 54", + "text": "rcp_ep_adc_render_registers() shall serialize cfg's whole TC18 §13.7.9.2 Table 54 register block into an RCP_EP_ADC_EP_FUNC_LEN-octet buffer at the documented offsets. SPLIT 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch): this id previously also bundled rcp_ep_adc_encode_reconfig_request()'s own, separate protocol-encoding contract -- a different function producing an ACF_ABB write request, not a register-block serialization -- under one id; that is now REQ-ADC-054. Directly unit-tested (test_render_registers_matches_table_offsets, test_render_registers_truncates_wide_fields). FIXED 2026-08-11 (c-RCP-AUDIT-06, issue #256 Group I): TC18 §12.7.1 Figure 18 defines one generic configuration request -- evt[2:0] = 111b, byte_msg_payload = a relative register start address within the addressed endpoint's EP_func section followed by configuration data -- usable against every endpoint type; rcp_ep_adc_decode_read_request() already correctly rejected evt[2:0] = 111b as RCP_EP_ADC_ERR_BAD_EVT (via acf.h's rcp_acf_evt_row2_is_plain()), but no counterpart function implemented that path at all until this fix.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.7.1 Configuration of endpoints + Figure 18, TC18.txt L2463-2484", + "tc18_master_id": "TC18-12.7.1-002" + }, + { + "id": "REQ-ADC-039", + "title": "rcp_ep_adc_apply_reconfig() validates, patches, and atomically adopts a configuration write", + "text": "rcp_ep_adc_apply_reconfig() shall decode the address+data payload TC18 §12.7.1 defines and patch cfg's Table 54 register block at octet granularity, then adopt the whole block atomically -- a write whose start_address+length exceeds RCP_EP_ADC_EP_FUNC_LEN is rejected and cfg left entirely unchanged (RCP_EP_ADC_RECONFIG_ERR_OUT_OF_RANGE), matching §12.7.1's own 'such a payload is to be ignored' rule; octets landing on a read-only register (EP_LEN, the reserved octet, or base_clk) are silently skipped while the rest of the span is still applied. SPLIT 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch): this id previously also bundled rcp_ep_adc_reconfig_strerror()'s own, separate never-NULL contract for a completely different function under one id; that is now REQ-ADC-055. FIXED 2026-08-11 (c-RCP-AUDIT-06, issue #256 Group I). Independently tested (test_apply_reconfig_writes_multi_register_span, test_apply_reconfig_writes_resolution_and_trigger_thresholds, test_apply_reconfig_ignores_read_only_registers, test_apply_reconfig_rejects_write_past_ep_len, test_apply_reconfig_rejects_payload_without_data).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.7.1 Configuration of endpoints, TC18.txt L2463-2484", + "tc18_master_id": "TC18-12.7.1-003" + }, + { + "id": "REQ-ADC-040", + "title": "adc_resolution, adc_trigger_min and adc_trigger_max registers of Table 54 are now modeled", + "text": "FIXED 2026-08-11 (c-RCP-AUDIT-06, issue #256 Group I): a previously-uncatalogued gap, found while scoping REQ-ADC-035/036's own register-block fix -- TC18 §13.7.9.2 Table 54 defines three further R/W registers rcp_ep_adc_functional_cfg_t carried no counterpart for at all: adc_resolution (0x000D, 8 bit, R/W -- the number of bits used of the ADC reading value, <=16), adc_trigger_min (0x000E, 16 bit, R/W -- the threshold below which the ADC trigger signal is set low), and adc_trigger_max (0x0010, 16 bit, R/W -- the threshold above which it is set high). Now modeled as rcp_ep_adc_functional_cfg_t.resolution/trigger_min/trigger_max, reachable via rcp_ep_adc_render_registers()/_apply_reconfig() (REQ-ADC-038/039). No dedicated named setter exists for any of the three (matching every other register-block-only field's own precedent across every endpoint type this session has fixed); only the generic §12.7.1 write path reaches them. Note this does not implement the trigger-signal evaluation logic itself (REQ-ADC-031's own five-trigger-output gap remains open) -- only the threshold/resolution configuration storage and its wire reachability.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.2 Table 54, TC18.txt L5114-5122", + "tc18_master_id": "TC18-13.7.9.2-001" + }, + { + "id": "REQ-ADC-041", + "title": "rcp_ep_adc_average_interval() returns NO_SIGNAL only when every sample in the interval timed out", + "text": "rcp_ep_adc_average_interval() shall return value == RCP_EP_PWM_IN_NO_SIGNAL only when every sample in the interval equals RCP_EP_PWM_IN_NO_SIGNAL. Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-004, which bundled this propagation clause with the exclude-from-mean clause under one id -- both were already independently tested before this split (test_average_interval_skips_no_signal_samples for REQ-ADC-004's exclusion clause, test_average_interval_all_no_signal_is_no_signal for this propagation clause), confirming the bundling. RESOLVED (issue #184, c-RCP-AUDIT-05), left honestly uncited rather than force-cited: same basis as REQ-ADC-003/004 -- TC18's ADC chapter defines no timeout/no-signal concept and no payload-sentinel convention to cite; this propagation rule is this codebase's own design for a failure mode TC18 does not address, not a TC18 citation gap.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented" + }, + { + "id": "REQ-ADC-042", + "title": "rcp_ep_adc_encode_response() returns a zeroed rcp_bytes_t for an invalid value_count", + "text": "rcp_ep_adc_encode_response() shall return a zeroed rcp_bytes_t when value_count is 0 or exceeds RCP_EP_ADC_MAX_VALUES. Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-011, which bundled this failure-path clause with the success-path encoding contract under one id. Independently tested (test_response_encode_rejects_zero_or_oversized_value_count) and independently mutation-tested: reverting the value_count==0/>MAX_VALUES guard while keeping REQ-ADC-011's own test intact leaves that test passing but fails this one, confirming the two clauses are genuinely independent.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.3 (\"Responses contain as much measurement values as requested by half the read size of a request.\"), TC18.txt L5162-5163", + "tc18_master_id": "TC18-13.7.9.3-002" + }, + { + "id": "REQ-ADC-043", + "title": "rcp_ep_adc_encode_read_request()'s frame carries no payload", + "text": "rcp_ep_adc_encode_read_request() shall produce a frame whose ACF_ABB payload is empty (byte_msg_payload length 0) -- how many measurement values a response should carry is conveyed by read_size alone (extraction §5.9.3). Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-025, which bundled this encode-side wire-format clause with rcp_ep_adc_decode_read_request()'s own separate round-trip contract. Previously untested -- no assertion anywhere in tests/test_ep_adc.c checked the encoded read request's payload length -- now proven by the new test_read_request_carries_no_payload(), and mutation-tested by temporarily encoding a nonzero-length payload to confirm the new test catches it.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.3 (\"The ADC request has no byte_msg_payload...\"), TC18.txt L5162", + "tc18_master_id": "TC18-13.7.9.3-001" + }, + { + "id": "REQ-ADC-044", + "title": "rcp_ep_adc_decode_read_request() rejects a misaddressed byte_bus_id", + "text": "rcp_ep_adc_decode_read_request() shall return RCP_EP_ADC_ERR_WRONG_BUS when byte_bus_id != expected_bus_id. Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-026. Independently tested (test_read_request_rejects_wrong_bus) and independently mutation-tested.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L3666-3710", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-ADC-045", + "title": "rcp_ep_adc_decode_read_request() rejects a non-READ op", + "text": "rcp_ep_adc_decode_read_request() shall return RCP_EP_ADC_ERR_WRONG_OP when op is not RCP_ACF_OP_READ. Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-026. Independently tested (test_read_request_rejects_wrong_op) and independently mutation-tested.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L3666-3710", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-ADC-046", + "title": "rcp_ep_adc_decode_read_request() rejects a nonzero evt[2:0]", + "text": "rcp_ep_adc_decode_read_request() shall return RCP_EP_ADC_ERR_BAD_EVT when evt[2:0] is not 0b000 -- TC18 §13.5 Table 33's only legal value for a plain request in ADC's endpoint-type row (ADC, PWM_IN, I2C, LIN, CAN, UART, ISELED, MDIO). Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-026. Independently tested (test_read_request_rejects_nonzero_evt) and independently mutation-tested.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33, TC18.txt L3666-3710", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-ADC-047", + "title": "rcp_ep_adc_decode_response() rejects a frame holding more values than the caller can hold", + "text": "rcp_ep_adc_decode_response() shall return RCP_EP_ADC_ERR_TOO_MANY_VALUES when the payload holds more values than max_values. Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-029. Independently tested (test_response_decode_rejects_more_values_than_caller_can_hold) and independently mutation-tested.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.5 Table 33 (ADC/PWM_IN/I²C/LIN/CAN/UART/ISELED/MDIO row), TC18.txt L3684-3693", + "tc18_master_id": "TC18-13.5-001" + }, + { + "id": "REQ-ADC-048", + "title": "the ADC endpoint's BELOW_MIN trigger fires on a downward crossing of adc_trigger_min", + "text": "rcp_ep_adc_trigger_evaluate() shall set RCP_EP_ADC_TRIGGER_BELOW_MIN in its returned bitmask iff the tracked previous value was >= trigger_min and the new value is < trigger_min (Table 53's 'falls below' wording) -- a genuine edge-triggered transition relative to rcp_ep_adc_trigger_state_t's own tracked previous value, not a level comparison against the current value alone; never fires on the state's first evaluate() call, when there is no previous value to compare against. Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-031. IMPLEMENTED, FIXED 2026-08-12 (issue #201 batch). Independently tested (test_trigger_evaluate_below_min_fires_once_per_crossing, test_trigger_evaluate_exact_threshold_value_still_crosses, test_trigger_evaluate_moving_exactly_to_threshold_does_not_fire_below) and independently mutation-tested: an off-by-one mutation loosening trigger_min's strict '<' comparison on the covering (moving-exactly-to-threshold) side was initially uncaught until test_trigger_evaluate_moving_exactly_to_threshold_does_not_fire_below was added (issue #201's own mutation-testing pass).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.1 Table 53, TC18.txt L5052-5058", + "tc18_master_id": "TC18-13.7.9.1-009" + }, + { + "id": "REQ-ADC-049", + "title": "the ADC endpoint's ABOVE_MIN trigger fires on an upward crossing of adc_trigger_min", + "text": "rcp_ep_adc_trigger_evaluate() shall set RCP_EP_ADC_TRIGGER_ABOVE_MIN in its returned bitmask iff the tracked previous value was <= trigger_min and the new value is > trigger_min (Table 53's 'rises above' wording), edge-triggered the same way as REQ-ADC-048's BELOW_MIN and never firing on the state's first evaluate() call. Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-031. IMPLEMENTED, FIXED 2026-08-12 (issue #201 batch). Independently tested (test_trigger_evaluate_above_min_fires_on_upward_crossing, test_trigger_evaluate_moving_exactly_to_threshold_does_not_fire_above, test_trigger_evaluate_large_jump_fires_multiple_triggers) and independently mutation-tested (same off-by-one class as REQ-ADC-048, caught by test_trigger_evaluate_moving_exactly_to_threshold_does_not_fire_above).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.1 Table 53, TC18.txt L5052-5058", + "tc18_master_id": "TC18-13.7.9.1-009" + }, + { + "id": "REQ-ADC-050", + "title": "the ADC endpoint's BELOW_MAX trigger fires on a downward crossing of adc_trigger_max", + "text": "rcp_ep_adc_trigger_evaluate() shall set RCP_EP_ADC_TRIGGER_BELOW_MAX in its returned bitmask iff the tracked previous value was >= trigger_max and the new value is < trigger_max, independent of trigger_min's own two triggers (REQ-ADC-048/049) and edge-triggered the same way. Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-031. IMPLEMENTED, FIXED 2026-08-12 (issue #201 batch). Independently tested (test_trigger_evaluate_max_crossings, test_trigger_evaluate_max_moving_exactly_to_threshold_does_not_fire) and independently mutation-tested (same off-by-one class as REQ-ADC-048, caught by test_trigger_evaluate_max_moving_exactly_to_threshold_does_not_fire).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.1 Table 53, TC18.txt L5052-5058", + "tc18_master_id": "TC18-13.7.9.1-009" + }, + { + "id": "REQ-ADC-051", + "title": "the ADC endpoint's ABOVE_MAX trigger fires on an upward crossing of adc_trigger_max", + "text": "rcp_ep_adc_trigger_evaluate() shall set RCP_EP_ADC_TRIGGER_ABOVE_MAX in its returned bitmask iff the tracked previous value was <= trigger_max and the new value is > trigger_max, independent of trigger_min's own two triggers (REQ-ADC-048/049) and edge-triggered the same way. Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-031. IMPLEMENTED, FIXED 2026-08-12 (issue #201 batch). Independently tested (test_trigger_evaluate_max_crossings, test_trigger_evaluate_max_moving_exactly_to_threshold_does_not_fire, test_trigger_evaluate_large_jump_fires_multiple_triggers) and independently mutation-tested (same off-by-one class as REQ-ADC-048).", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.1 Table 53, TC18.txt L5052-5058", + "tc18_master_id": "TC18-13.7.9.1-009" + }, + { + "id": "REQ-ADC-052", + "title": "the ADC endpoint's MEASUREMENT_FINISHED trigger composes independently with the other four", + "text": "rcp_ep_adc_trigger_evaluate() shall set RCP_EP_ADC_TRIGGER_MEASUREMENT_FINISHED in its returned bitmask iff its caller-supplied measurement_finished argument is true, independently of trigger_min/trigger_max and of rcp_ep_adc_trigger_state_t's tracked previous value -- it has no threshold or previous-value concept of its own and composes freely with any of the other four triggers firing in the same call (Table 53's five signals are independent, not mutually exclusive). Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-031. IMPLEMENTED, FIXED 2026-08-12 (issue #201 batch). Independently tested (test_trigger_evaluate_measurement_finished_composes_with_edge_triggers, test_trigger_evaluate_first_call_never_fires_edge_triggers) and independently mutation-tested.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§13.7.9.1 Table 53, TC18.txt L5052-5058", + "tc18_master_id": "TC18-13.7.9.1-009" + }, + { + "id": "REQ-ADC-053", + "title": "rcp_ep_adc_cadence_response_ready() reports whether enough averaged values are pending to send a response", + "text": "rcp_ep_adc_cadence_response_ready() shall return true iff pending_value_count >= combine_avg_values -- the one comparison underlying all three of TC18 §13.7.9.2's cadence cases. Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-037, which bundled this function's own contract with rcp_ep_adc_cadence_case()'s separate classification contract under one id. Directly unit-tested (test_cadence_response_ready_true_when_pending_meets_combine, test_cadence_response_ready_false_when_pending_short, test_cadence_response_ready_zero_combine_always_ready) plus an end-to-end walk of the ACCUMULATE and FAN_OUT cases across multiple simulated executions/responses (test_cadence_response_ready_drives_accumulate_case_across_executions, test_cadence_response_ready_drives_fan_out_case_across_responses). PARTIAL (retains REQ-ADC-037's original 2026-08-13 dispatch-wiring narrative, since it describes this function's own real-dispatch integration, not cadence_case()'s): DISPATCH-WIRING HALF CLOSED (issue #336): test_tc18_gaps_ep2.c's own adc_dispatch_handler() (an rcp_mock_endpoint_handler_fn registered via the existing, unmodified rcp_mock_server_add_endpoint()) calls rcp_ep_adc_cadence_response_ready() on every dispatched request and honors its result end-to-end through a real mock.c dispatch() path: test_adc_dispatch_accumulates_across_executions_before_responding() proves the RCP_EP_ADC_CADENCE_ACCUMULATE case withholds a synchronous response across two executions and produces one, with all three accumulated values in correct order, on the third -- the same 'mock.c never calls into ep_*.c directly; a caller-registered handler is the documented mechanism' disposition already established for REQ-GPIO-035/036. STILL PARTIAL: this dispatch-level test fixture deliberately skips layer 1 (rcp_ep_adc_average_interval(), already independently tested and exercised end-to-end in a non-dispatch context) -- it injects one already-averaged value per execution directly, rather than deriving it from real per-sample averaging within that execution, so no single test yet exercises the full raw-samples-to-response pipeline through a real dispatch path. Assembling a ready response's own value array and computing its transaction_num remain the caller's own bookkeeping, by design (TC18 gives no instruction for HOW a caller should track per-value provenance across executions) -- not a gap, this module correctly does not make that invention unilaterally.", + "standard": "iso26262", + "level": "QM", + "asil": "QM", + "scope": "tc18-gap", + "status": "partial", + "tc18": "§13.7.9.2 (\"When adc_combine_avg_values > adc_avg_intervals_per_request... When adc_combine_avg_values = adc_avg_intervals_per_request... When adc_combine_avg_values < adc_avg_intervals_per_request...\"), TC18.txt L5128-5133" + }, + { + "id": "REQ-ADC-054", + "title": "rcp_ep_adc_encode_reconfig_request() encodes the generic §12.7.1 configuration-write request", + "text": "rcp_ep_adc_encode_reconfig_request() shall encode an ACF_ABB write request (op=WRITE, evt[2:0]=111b) carrying a 16-bit big-endian start address followed by data, matching PWM_OUT's/GPIO's/SPI's/I2C's/UART's/LIN's own encode_reconfig_request() shape. Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-038, which bundled this function's own contract with rcp_ep_adc_render_registers()'s separate register-block-serialization contract under one id. FIXED 2026-08-11 (c-RCP-AUDIT-06, issue #256 Group I). Independently tested (test_reconfig_request_round_trip, test_encode_reconfig_request_rejects_empty_data) and independently mutation-tested.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.7.1 Configuration of endpoints + Figure 18, TC18.txt L2463-2484", + "tc18_master_id": "TC18-12.7.1-002" + }, + { + "id": "REQ-ADC-055", + "title": "rcp_ep_adc_reconfig_strerror() never returns NULL", + "text": "rcp_ep_adc_reconfig_strerror() shall never return NULL, including for an unrecognized rcp_ep_adc_reconfig_errc_t value. Split 2026-08-18 (c-RCP-18 audit, issue #533 REQ-ADC batch) from REQ-ADC-039, which bundled this function's own contract with rcp_ep_adc_apply_reconfig()'s separate validate/patch/adopt contract under one id. FIXED 2026-08-11 (c-RCP-AUDIT-06, issue #256 Group I). Independently tested (test_reconfig_strerror_never_null) and independently mutation-tested.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "scope": "tc18", + "status": "implemented", + "tc18": "§12.7.1 Configuration of endpoints, TC18.txt L2463-2484", + "tc18_master_id": "TC18-12.7.1-003" } ] -} \ No newline at end of file +} diff --git a/tests/test_acf.cpp b/tests/test_acf.cpp index d4fd5a3..0a7f932 100644 --- a/tests/test_acf.cpp +++ b/tests/test_acf.cpp @@ -37,6 +37,7 @@ // fusa:test REQ-ACF-052 // fusa:test REQ-ACF-053 // fusa:test REQ-WIREERR-001 +// fusa:test REQ-ADC-034 // Tests for rcp/acf.hpp — the ACF_ABB/ACF_GBB message-format half of the TC18 // wire codec (ROADMAP.md milestone 44, "Wire Format Core", v2.0.0; split @@ -779,7 +780,7 @@ TEST_CASE("compound_wait_match caps status to payload_length (the specification' REQUIRE_FALSE(compound_wait_match(0x0, payload, sizeof(payload), status, sizeof(status))); } -TEST_CASE("compound_wait_match exact-match mode (evt[2:0] = 000b)", "[acf][REQ-ACF-026]") { +TEST_CASE("compound_wait_match exact-match mode (evt[2:0] = 000b)", "[acf][REQ-ACF-026][REQ-ADC-034]") { const uint8_t payload[2] = {0x01, 0x02}; const uint8_t equal[2] = {0x01, 0x02}; const uint8_t differs[2] = {0x01, 0x03}; diff --git a/tests/test_adc.cpp b/tests/test_adc.cpp index 2e44cf5..bec72b3 100644 --- a/tests/test_adc.cpp +++ b/tests/test_adc.cpp @@ -29,11 +29,15 @@ // fusa:test REQ-ADC-029 // fusa:test REQ-ADC-030 // fusa:test REQ-ADC-031 +// fusa:test REQ-ADC-032 // fusa:test REQ-ADC-033 +// fusa:test REQ-ADC-035 +// fusa:test REQ-ADC-036 // fusa:test REQ-ADC-037 // fusa:test REQ-ADC-038 // fusa:test REQ-ADC-039 // fusa:test REQ-ADC-040 +// fusa:test REQ-ADC-041 // fusa:test REQ-ADC-042 // fusa:test REQ-ADC-043 // fusa:test REQ-ADC-044 @@ -151,6 +155,16 @@ TEST_CASE("collect_response_values packs averaged values in capture order, verba REQUIRE(out == std::vector{10, kAdcNoSignal, 30}); } +TEST_CASE("collect_response_values packs exactly value_count values -- the leading ones -- when " + "more averages are available than requested", + "[adc][REQ-ADC-007]") { + std::vector avg{{10, 0}, {20, 0}, {30, 0}, {40, 0}}; + std::vector out; + auto n = collect_response_values(avg, 2, out); + REQUIRE(n == 2); + REQUIRE(out == std::vector{10, 20}); +} + TEST_CASE("collect_response_values reports a short count without touching unwritten entries", "[adc][REQ-ADC-008]") { std::vector avg{{10, 1}, {20, 2}}; @@ -290,6 +304,18 @@ TEST_CASE("trigger_evaluate never fires an edge trigger on the first call", "[ad REQUIRE(s.has_previous); } +TEST_CASE("an ADC measurement value is fixed at 16 bits, matching TC18's byte_msg_payload layout", + "[adc][REQ-ADC-032]") { + // kAdcValueLen is the single source of truth every wire-level ADC + // encode/decode path (encode_response/decode_response, response_ + // value_count) derives its byte-count arithmetic from -- pin it + // directly at 16 bits (RCP_EP_ADC_VALUE_LEN's own value in c-RCP) so + // any future change to that constant is caught here explicitly, not + // just as an incidental side effect of an unrelated codec test. + REQUIRE(kAdcValueLen == sizeof(uint16_t)); + REQUIRE(kAdcValueLen == 2); +} + TEST_CASE("trigger_evaluate BELOW_MIN fires on a downward crossing of trigger_min", "[adc][REQ-ADC-048]") { AdcTriggerState s; @@ -475,6 +501,15 @@ TEST_CASE("AdcErrc reports a non-empty, category-correct message for every value REQUIRE(ec.category() == adc_category()); REQUIRE_FALSE(ec.message().empty()); } + // An out-of-range/unrecognized code (covers both AdcErrc's own general + // default branch, REQ-ADC-024, and the reconfig-specific codes 9/10 + // folded into the same category, REQ-ADC-055 -- c-RCP's + // rcp_ep_adc_strerror()/rcp_ep_adc_reconfig_strerror() are two separate + // functions each tested with an out-of-range value; this category's + // message() merges both, so one out-of-range assertion here covers both + // ids' "including an out-of-range value" clause). + auto ec = make_error_code(static_cast(99)); + REQUIRE_FALSE(ec.message().empty()); } TEST_CASE("AdcErrc::no_signal's message does not claim an invented ADC_NO_SIGNAL spec identifier", diff --git a/tests/test_i2c.cpp b/tests/test_i2c.cpp index 82de407..f9d2657 100644 --- a/tests/test_i2c.cpp +++ b/tests/test_i2c.cpp @@ -574,7 +574,7 @@ TEST_CASE("I2cEndpoint::handle_request rejects every reserved evt[2:0] value (00 } TEST_CASE("I2cEndpoint::handle_request reports config_write_not_supported for evt[2:0]==111b", - "[i2c][REQ-I2C-012]") { + "[i2c][REQ-I2C-007]") { I2cEndpoint ep; auto ec = ep.handle_request(/*evt_op=*/7, {0x00, 0xAB}, {}); REQUIRE(ec == make_error_code(I2cErrc::config_write_not_supported));