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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions .fusa-reqs.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@
},
{
"id": "REQ-MOCK-001",
"title": "Server starts HW_UNCONFIGURED with a representative eight-endpoint register map",
"text": "rcp::mock::Server shall construct with rcp::lifecycle::ServerLifecycle in state HwUnconfigured and an rcp::regmap::RegisterMap whose endpoint_count, generic_configs, functional_configs, and ep_id_mapping describe exactly eight endpoints: GPIO at endpoint id/byte_bus_id 1, SPI at endpoint id/byte_bus_id 2, I2C at endpoint id/byte_bus_id 3, ADC at endpoint id/byte_bus_id 4, PWM_IN at endpoint id/byte_bus_id 5, LIN at endpoint id/byte_bus_id 6, CAN at endpoint id/byte_bus_id 7, and UART at endpoint id/byte_bus_id 8.",
"title": "Server starts HW_UNCONFIGURED with a representative nine-endpoint register map",
"text": "rcp::mock::Server shall construct with rcp::lifecycle::ServerLifecycle in state HwUnconfigured and an rcp::regmap::RegisterMap whose endpoint_count, generic_configs, functional_configs, and ep_id_mapping describe exactly nine endpoints: GPIO at endpoint id/byte_bus_id 1, SPI at endpoint id/byte_bus_id 2, I2C at endpoint id/byte_bus_id 3, ADC at endpoint id/byte_bus_id 4, PWM_IN at endpoint id/byte_bus_id 5, LIN at endpoint id/byte_bus_id 6, CAN at endpoint id/byte_bus_id 7, UART at endpoint id/byte_bus_id 8, and ISELED at endpoint id/byte_bus_id 9.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
Expand Down Expand Up @@ -268,6 +268,24 @@
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-MOCK-023",
"title": "ISELED dispatch applies Table 33 Row 2 evt[2:0] classification before touching endpoint state, decoding/encoding through ISELED's own Figure 40/41 codec",
"text": "rcp::mock::Server::dispatch, for a request addressed to the ISELED endpoint while RcpConfigured, shall decode the request's byte_msg_payload via iseled::decode_iseled_request into an IseledRequest and drive iseled::IseledEndpoint::handle_request with the request's evt[2:0] field: a Plain (000b) request shall transact the decoded IseledRequest against whatever IseledResponse set_iseled_response() last scripted (default IseledResponse{0, 0}) and be answered as a ReadResponse whose byte_msg_payload is iseled::encode_iseled_response(IseledEndpoint::last_response()), a Reserved (001b-110b) evt shall be rejected with endpoint::EndpointErrc::reserved_evt_row2 (wire error code UNSUPPORTED_CMD) without recording anything, and a ConfigWrite (111b) evt shall be rejected with iseled::IseledErrc::config_write_not_supported (wire error code UNSUPPORTED_CMD) rather than crashing or being treated as a plain transaction.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B",
"tc18": "§13.5 Table 33 (\"ADC, PWM_IN, I²C, LIN, CAN, UART, ISELED, MDIO: 000b to 110b reserved – request to be rejected with error code = UNSUPPORTED_CMD\" / \"111b: The byte_msg_payload is not presented to the interface but used to change the configuration of the endpoint (see 12.7.1)\"), TC18.txt L4085-4092; corroborating worked example resolving the evt=000b ambiguity in Table 33's own favor: §13.7.9.3 Figure 34 (\"RC Client sends a standard read request\", ADC endpoint, evt field all-zero), TC18.txt L5590-5607",
"tc18_master_id": "TC18-13.5-001"
},
{
"id": "REQ-MOCK-024",
"title": "Operational ISELED requests are rejected before RCP_CONFIGURED, same gating as GPIO/SPI/I2C/ADC/PWM_IN/LIN/CAN/UART",
"text": "rcp::mock::Server::dispatch, for a request addressed to the ISELED endpoint while the server's lifecycle state is not RcpConfigured, shall return regmap::RegMapErrc::request_rejected and an ErrorResponse without touching the endpoint's live state, the same operational-request gating REQ-MOCK-006/REQ-MOCK-012/REQ-MOCK-014/REQ-MOCK-016/REQ-MOCK-018/REQ-MOCK-020/REQ-MOCK-022 already apply to GPIO/SPI/I2C/ADC/PWM_IN/LIN/CAN/UART.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-UDP-001",
"title": "Frame round-trips an NTSCF-framed ACF_ABB request",
Expand Down Expand Up @@ -3390,6 +3408,27 @@
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-ISELED-006",
"title": "IseledEndpoint::handle_request applies Table 33 Row 2 evt[2:0] classification before transacting",
"text": "rcp::iseled::IseledEndpoint::handle_request shall classify its evt_op argument via rcp::endpoint::evt_row2_kind_of (masking to the low 3 bits first) and, for EvtRow2Kind::Plain, shall delegate to transact(request, response) with both arguments unchanged; for EvtRow2Kind::Reserved, shall return endpoint::EndpointErrc::reserved_evt_row2 without recording anything as the last request/response (last_request()/last_response() left untouched) and without firing TransferComplete.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B",
"tc18": "§13.5 Table 33 (\"ADC, PWM_IN, I²C, LIN, CAN, UART, ISELED, MDIO: 000b to 110b reserved – request to be rejected with error code = UNSUPPORTED_CMD\"), TC18.txt L4085-4092; corroborating worked example resolving the evt=000b ambiguity in Table 33's own favor: §13.7.9.3 Figure 34 (\"RC Client sends a standard read request\", ADC endpoint, evt field all-zero), TC18.txt L5590-5607",
"tc18_master_id": "TC18-13.5-001",
"severity": "cybersecurity"
},
{
"id": "REQ-ISELED-007",
"title": "IseledEndpoint::handle_request reports config-write (evt[2:0]==111b) as not yet supported",
"text": "rcp::iseled::IseledEndpoint::handle_request, for EvtRow2Kind::ConfigWrite (evt[2:0]==111b), shall return IseledErrc::config_write_not_supported without recording anything as the last request/response and without crashing, rather than silently accepting the request as an ordinary transaction or silently doing nothing; full §12.7.1 configuration-write handling is deliberately deferred to a follow-up milestone, the same scope decision I2C's I2cErrc::config_write_not_supported, ADC's AdcErrc::config_write_not_supported, PWM_IN's PwmErrc::config_write_not_supported, LIN's LinErrc::config_write_not_supported, CAN's CanErrc::config_write_not_supported, and UART's UartErrc::config_write_not_supported already made. IseledErrc::config_write_not_supported shall report a non-empty diagnostic message in its own error_category.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B",
"tc18": "§12.7.1 (\"This can be done by setting evt[2:0] = 111b in request as described above.\"; Figure 19 – \"Configuration request\"; \"The data of the byte_msg_payload from a write request is written into the section of the EP that is addressed by the byte_bus_id.\"), TC18.txt L2844-2865",
"tc18_master_id": "TC18-12.7.1-001"
},
{
"id": "REQ-MDIO-001",
"title": "MDIO's ep_type id is 0x0D",
Expand Down
90 changes: 89 additions & 1 deletion include/rcp/iseled.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// fusa:req REQ-ISELED-003
// fusa:req REQ-ISELED-004
// fusa:req REQ-ISELED-005
// fusa:req REQ-ISELED-006
// fusa:req REQ-ISELED-007

// ISELED endpoint (ep_type 0x0C) — the OPEN Alliance TC18 Remote Control
// Protocol Specification v0.5.1_RC's native ISELED daisy-chain framing: a
Expand Down Expand Up @@ -45,12 +47,30 @@
// IseledSignal::NativeCrcError is removed along with it, leaving
// IseledSignal::TransferComplete as the endpoint's only trigger signal.
//
// Table 30/33 Row 2 evt[2:0] validation (post-v2.7.0, seventh endpoint type
// after I2C, ADC, PWM_IN, LIN, CAN, and UART): IseledEndpoint::handle_request
// is this header's own wiring of rcp::endpoint::evt_row2_kind_of — the
// shared 3-way evt[2:0] classifier for Table 33's {ADC, PWM_IN, I2C, LIN,
// CAN, UART, ISELED, MDIO} row — into ISELED's request decode, following the
// exact shape rcp/i2c.hpp's I2cEndpoint::handle_request, rcp/adc.hpp's
// AdcEndpoint::handle_request, rcp/pwm.hpp's PwmInEndpoint::handle_request,
// rcp/lin.hpp's LinEndpoint::handle_request, rcp/can.hpp's CanEndpoint::
// handle_request, and rcp/uart.hpp's UartEndpoint::handle_request
// established. This is a completely separate, TC18-Table-33-derived
// concern from the Figure 40/41 wire-format fix directly above — it does
// not touch, reinterpret, or extend IseledRequest's/IseledResponse's field
// shapes, or the encode_iseled_request/decode_iseled_request/
// encode_iseled_response/decode_iseled_response codec, in any way. See
// handle_request's own doc comment below for why a Reserved or ConfigWrite
// evt must never reach transact().
//
// Field names and behavior below implement TC18's *behavior* as described in
// an internal structured extraction of the specification named above; no
// text from that document is reproduced here. The concrete request `data`
// vector representation and trigger-signal id encoding chosen in this file
// are this implementation's own, same as the equivalent disclaimers in
// rcp/avtp.hpp, rcp/regmap.hpp, rcp/endpoint.hpp, and rcp/e2e.hpp.
// rcp/avtp.hpp, rcp/regmap.hpp, rcp/endpoint.hpp, rcp/e2e.hpp, rcp/i2c.hpp,
// rcp/adc.hpp, rcp/pwm.hpp, rcp/lin.hpp, rcp/can.hpp, and rcp/uart.hpp.
#pragma once

#include <rcp/avtp.hpp>
Expand Down Expand Up @@ -91,6 +111,15 @@ struct IseledResponse {

enum class IseledErrc : int {
field_out_of_range = 1, // instruction/address/data exceeds its documented wire field width
// evt_row2_kind_of classified the request as ConfigWrite (evt[2:0] ==
// 111b, §12.7.1). This milestone's follow-up deliberately does not
// implement the configuration-write shape (relative EP_functional-
// config start address + configuration data) — see handle_request's
// own comment. Reported explicitly rather than silently accepted as a
// plain transaction or silently ignored, same as I2C's, ADC's,
// PWM_IN's, LIN's, CAN's, and UART's own config_write_not_supported
// variants.
config_write_not_supported = 2,
};

inline const std::error_category& iseled_category() noexcept {
Expand All @@ -100,6 +129,8 @@ inline const std::error_category& iseled_category() noexcept {
switch (static_cast<IseledErrc>(ev)) {
case IseledErrc::field_out_of_range:
return "rcp/iseled: instruction/address/data exceeds its wire field width";
case IseledErrc::config_write_not_supported:
return "rcp/iseled: evt[2:0]=111b configuration-write requests are not yet implemented";
default:
return "rcp/iseled: unknown error";
}
Expand Down Expand Up @@ -228,6 +259,63 @@ class IseledEndpoint {
return {};
}

// handle_request is ISELED's request-decode entry point — the piece
// this header previously had none of, mirroring rcp::i2c::
// I2cEndpoint::handle_request's shape (this repo's seventh Table 33
// Row 2 endpoint type after I2C, ADC, PWM_IN, LIN, CAN, and UART). It
// classifies the incoming request's evt[2:0] field via rcp::endpoint::
// evt_row2_kind_of before doing anything else, so a Reserved value can
// never reach transact() and be misread as an ordinary transaction,
// and a ConfigWrite value can never be silently accepted or silently
// dropped:
// - Plain (evt[2:0] == 000b): delegates straight to transact(request,
// response) with both arguments unchanged — ISELED's existing
// request/response transaction model (extraction §13.7.12.3)
// already IS this row's correct "plain request" behavior; evt[2:0]
// carries no combinable value or channel selector for this row.
// - Reserved (evt[2:0] in 001b-110b): returns
// endpoint::EndpointErrc::reserved_evt_row2 without recording
// anything (last_request_/last_response_ are left exactly as they
// were, and TransferComplete does not fire) — TC18 requires this be
// rejected with error code UNSUPPORTED_CMD.
// - ConfigWrite (evt[2:0] == 111b): §12.7.1's configuration-write
// shape targets the ISELED EP's own functional-config block, not a
// daisy-chain transaction at all. Full handling is deliberately out
// of scope for this milestone (nontrivial — it needs
// EP_functional-config wiring this header does not yet have, the
// same gap I2C's, ADC's, PWM_IN's, LIN's, CAN's, and UART's own
// handle_request comments defer for the identical reason); this
// returns IseledErrc::config_write_not_supported rather than
// crashing, silently accepting the request as a transaction, or
// silently doing nothing.
//
// NOT to be confused with this header's own Figure 40/41 wire-format
// fix directly above (the 12-bit address/data field widths, and the
// removed invented CRC-8): that fix concerns what IseledRequest's and
// IseledResponse's *fields* mean and how wide they are; Table 33's
// evt[2:0] classification is an entirely separate, orthogonal concern
// about which *kind* of request evt[2:0] itself selects. Reading
// evt[2:0] as if it also selected or combined with instruction/address/
// data, or inventing any encoding of those fields beyond what
// validate_request/validate_response and encode_iseled_request/
// decode_iseled_request/encode_iseled_response/decode_iseled_response
// already define, would be exactly the kind of invented, non-spec-
// derived encoding this header's own top-of-file comment documents
// having to remove once already. handle_request below calls the same
// shared evt_row2_kind_of every other Row 2 endpoint type uses and
// invents nothing of its own.
std::error_code handle_request(uint8_t evt_op, IseledRequest request, IseledResponse response) {
switch (endpoint::evt_row2_kind_of(evt_op)) {
case endpoint::EvtRow2Kind::Plain:
return transact(std::move(request), std::move(response));
case endpoint::EvtRow2Kind::Reserved:
return endpoint::make_error_code(endpoint::EndpointErrc::reserved_evt_row2);
case endpoint::EvtRow2Kind::ConfigWrite:
return make_error_code(IseledErrc::config_write_not_supported);
}
return endpoint::make_error_code(endpoint::EndpointErrc::reserved_evt_row2); // unreachable
}

const IseledRequest& last_request() const noexcept { return last_request_; }
const IseledResponse& last_response() const noexcept { return last_response_; }
endpoint::TriggerRegistry& triggers() noexcept { return triggers_; }
Expand Down
Loading
Loading