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 four-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 four 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, and ADC at endpoint id/byte_bus_id 4.",
"title": "Server starts HW_UNCONFIGURED with a representative six-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 six 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, and LIN at endpoint id/byte_bus_id 6.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
Expand Down Expand Up @@ -214,6 +214,24 @@
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-MOCK-017",
"title": "LIN dispatch applies Table 33 Row 2 evt[2:0] classification before touching endpoint state",
"text": "rcp::mock::Server::dispatch, for a request addressed to the LIN endpoint while RcpConfigured, shall decode the request's evt[2:0] field via endpoint::evt_row2_kind_of and drive lin::LinEndpoint::handle_request with it: a Plain (000b) request shall be answered as a ReadResponse carrying whatever bytes set_lin_response last scripted, a Reserved (001b-110b) evt shall be rejected with endpoint::EndpointErrc::reserved_evt_row2 (wire error code UNSUPPORTED_CMD) without recording anything as sent/received, and a ConfigWrite (111b) evt shall be rejected with lin::LinErrc::config_write_not_supported (wire error code UNSUPPORTED_CMD) rather than crashing or being treated as a plain transfer.",
"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-018",
"title": "Operational LIN requests are rejected before RCP_CONFIGURED, same gating as GPIO/SPI/I2C/ADC/PWM_IN",
"text": "rcp::mock::Server::dispatch, for a request addressed to the LIN 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 already apply to GPIO/SPI/I2C/ADC/PWM_IN.",
"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 @@ -3159,6 +3177,27 @@
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-LINEP-005",
"title": "LinEndpoint::handle_request applies Table 33 Row 2 evt[2:0] classification before transferring",
"text": "rcp::lin::LinEndpoint::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 transfer() with out_bytes/in_bytes/responded unchanged; for EvtRow2Kind::Reserved, shall return endpoint::EndpointErrc::reserved_evt_row2 without recording anything as sent or received.",
"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-LINEP-006",
"title": "LinEndpoint::handle_request reports config-write (evt[2:0]==111b) as not yet supported",
"text": "rcp::lin::LinEndpoint::handle_request, for EvtRow2Kind::ConfigWrite (evt[2:0]==111b), shall return LinErrc::config_write_not_supported without recording anything as sent or received and without crashing, rather than silently accepting the request as an ordinary transfer 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, and PWM_IN's PwmErrc::config_write_not_supported already made. LinErrc::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-CANEP-001",
"title": "CAN's ep_type id is 0x0B",
Expand Down
94 changes: 92 additions & 2 deletions include/rcp/lin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// fusa:req REQ-LINEP-002
// fusa:req REQ-LINEP-003
// fusa:req REQ-LINEP-004
// fusa:req REQ-LINEP-005
// fusa:req REQ-LINEP-006

// LIN commander endpoint (ep_type 0x06) — the OPEN Alliance TC18 Remote
// Control Protocol Specification v0.5.1_RC's raw-byte-pusher model for LIN:
Expand Down Expand Up @@ -30,12 +32,49 @@
// transfer`'s raw byte-stream shape for exactly this reason: both endpoint
// types push/pull opaque bytes and leave interpretation to the caller.
//
// Table 30/33 Row 2 evt[2:0] validation (post-v2.7.0, fourth endpoint type
// after I2C, ADC, and PWM_IN): LinEndpoint::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 LIN's request decode, following the exact shape
// rcp/i2c.hpp's I2cEndpoint::handle_request, rcp/adc.hpp's
// AdcEndpoint::handle_request, and rcp/pwm.hpp's PwmInEndpoint::
// handle_request established. Plain (evt[2:0]==000b) delegates straight to
// the existing transfer() above, unchanged — LIN's raw-byte-pusher model
// already IS this row's correct "plain request" behavior, the same
// reasoning I2C's own handle_request gave for its identical shape. Reserved
// (001b-110b) is rejected with endpoint::EndpointErrc::reserved_evt_row2
// without touching out_bytes/in_bytes or any transfer state. ConfigWrite
// (evt[2:0]==111b, §12.7.1) is reported as the new
// LinErrc::config_write_not_supported rather than crashing or silently
// accepted as a plain transfer — LIN has no EP_functional-config wiring in
// this codebase yet (same gap I2C's, ADC's, and PWM_IN's own handle_request
// comments call out for their own endpoint types), so full §12.7.1 handling
// is out of scope here too.
//
// NOT to be confused with §13.7.10.1's separate "conditions given by
// evt[2:0]" text describing pending-read-request byte-sequence matching
// against bus traffic (LIN's own analog of I2C's compound_wait_matches_bits
// — a different mechanism, out of this milestone's scope, not modeled by
// this header at all): that text is about compound-wait match conditions,
// not about Table 33's top-level Plain/Reserved/ConfigWrite request
// classification handle_request implements below. Reading the two as one
// "evt[2:0] selects a comparison mode" scheme would be exactly the kind of
// invented, non-spec-derived encoding this codebase has had to remove
// elsewhere once discovered (e.g. rcp/iseled.hpp's and rcp/mdio.hpp's own
// header comments on previously invented, non-spec-derived field encodings
// later corrected) — handle_request below calls the same shared
// evt_row2_kind_of every other Row 2 endpoint type uses and invents nothing
// of its own; §13.7.10.1's pending-read match semantics remain unimplemented
// here, called out rather than silently guessed at.
//
// 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 transfer-shape
// 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/i2c.hpp.
// rcp/regmap.hpp, rcp/endpoint.hpp, rcp/i2c.hpp, rcp/adc.hpp, and
// rcp/pwm.hpp.
#pragma once

#include <rcp/endpoint.hpp>
Expand All @@ -57,6 +96,14 @@ namespace lin {

enum class LinErrc : int {
no_response = 1,
// 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 transfer or silently ignored, same as I2C's, ADC's, and
// PWM_IN's own config_write_not_supported variants.
config_write_not_supported = 2,
};

inline const std::error_category& lin_category() noexcept {
Expand All @@ -65,7 +112,9 @@ inline const std::error_category& lin_category() noexcept {
std::string message(int ev) const override {
switch (static_cast<LinErrc>(ev)) {
case LinErrc::no_response: return "rcp/lin: no response observed on the bus";
default: return "rcp/lin: unknown error";
case LinErrc::config_write_not_supported:
return "rcp/lin: evt[2:0]=111b configuration-write requests are not yet implemented";
default: return "rcp/lin: unknown error";
}
}
};
Expand Down Expand Up @@ -114,6 +163,47 @@ class LinEndpoint {
return {};
}

// handle_request is LIN's request-decode entry point — the piece this
// header previously had none of, mirroring rcp::i2c::I2cEndpoint::
// handle_request's shape exactly (this repo's fourth Table 33 Row 2
// endpoint type after I2C, ADC, and PWM_IN). 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 transfer()
// and be misread as an ordinary transfer, and a ConfigWrite value can
// never be silently accepted or silently dropped:
// - Plain (evt[2:0] == 000b): delegates straight to transfer() with
// `out_bytes`/`in_bytes`/`responded` unchanged — LIN's existing
// raw-byte-pusher transfer model (extraction §13.7.10.3) already IS
// this row's correct "plain request" behavior; evt[2:0] carries no
// combinable value or channel selector for this row the way it
// does for GPIO/PWM_OUT or SPI.
// - Reserved (evt[2:0] in 001b-110b): returns
// endpoint::EndpointErrc::reserved_evt_row2 without touching any
// endpoint state or recording anything as sent/received — TC18
// requires this be rejected with error code UNSUPPORTED_CMD.
// - ConfigWrite (evt[2:0] == 111b): §12.7.1's configuration-write
// shape targets the LIN EP's own functional-config block (relative
// start address + configuration data), not a bus transfer 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, and PWM_IN's own
// handle_request comments defer for the identical reason); this
// returns LinErrc::config_write_not_supported rather than
// crashing, silently accepting the request as a transfer, or
// silently doing nothing.
std::error_code handle_request(uint8_t evt_op, std::vector<uint8_t> out_bytes,
std::vector<uint8_t> in_bytes, bool responded = true) {
switch (endpoint::evt_row2_kind_of(evt_op)) {
case endpoint::EvtRow2Kind::Plain:
return transfer(std::move(out_bytes), std::move(in_bytes), responded);
case endpoint::EvtRow2Kind::Reserved:
return endpoint::make_error_code(endpoint::EndpointErrc::reserved_evt_row2);
case endpoint::EvtRow2Kind::ConfigWrite:
return make_error_code(LinErrc::config_write_not_supported);
}
return endpoint::make_error_code(endpoint::EndpointErrc::reserved_evt_row2); // unreachable
}

const std::vector<uint8_t>& last_sent() const noexcept { return last_out_; }
const std::vector<uint8_t>& last_received() const noexcept { return last_in_; }
endpoint::TriggerRegistry& triggers() noexcept { return triggers_; }
Expand Down
Loading
Loading