diff --git a/src/acf.rs b/src/acf.rs index 700da2e..d544c8b 100644 --- a/src/acf.rs +++ b/src/acf.rs @@ -202,12 +202,12 @@ pub const BYTE_MESSAGE_INFO_LEN: usize = 8; /// row 2's 4-bit `evt` nibble (octet 4 bits 7:4). /// /// The split into `ack` + `sub_opcode` is exactly TC18 §13.5's own split of -/// the `evt` nibble for **requests** (TC18.txt lines 3672-3673): "event bits +/// the `evt` nibble for **requests** (TC18.txt lines 4071-4072): "event bits /// evt[2:0] are used to control the usage of the byte_msg_payload" /// ([`Evt::sub_opcode`]) and "evt[3] is used to request an acknowledge. I.e. /// evt[3]=1 requests acknowledge" ([`Evt::ack`]). /// -/// Note that TC18 §11.3 Table 15 gives the *response* direction a different, +/// Note that TC18 §11.3 Table 17 gives the *response* direction a different, /// whole-nibble reading of the same four bits (0x0 simple/data/error, 0x1…0x8 /// a further-responses counter, 0x9…0xE reserved, 0xF acknowledge) which this /// two-field split does not model — see requirement `REQ-RESP-004`. @@ -217,11 +217,11 @@ pub const BYTE_MESSAGE_INFO_LEN: usize = 8; //fusa:req REQ-EVT-002 pub struct Evt { /// The ack-flag bit of `evt` — TC18 §13.5's `evt[3]`, which a request - /// sets to 1 to request an acknowledge (TC18.txt line 3673). + /// sets to 1 to request an acknowledge (TC18.txt line 4072). pub ack: bool, /// The 3-bit sub-opcode of `evt` — TC18 §13.5's `evt[2:0]`, which /// controls the endpoint-specific usage of the `byte_msg_payload` - /// (TC18.txt line 3672). Valid range is `0..=EVT_SUB_OPCODE_MAX`. + /// (TC18.txt line 4071). Valid range is `0..=EVT_SUB_OPCODE_MAX`. pub sub_opcode: u8, } @@ -230,7 +230,7 @@ impl Evt { /// (`ack << 3 | sub_opcode`), the same arithmetic /// [`encode_byte_message_info`] uses. Needed by /// [`ByteMessageInfo::response_kind`], which reads `evt` under TC18 - /// §11.3 Table 15's whole-nibble response encoding rather than this + /// §11.3 Table 17's whole-nibble response encoding rather than this /// type's own request-side ack+sub_opcode split — see this struct's /// doc comment. pub fn raw_nibble(&self) -> u8 { @@ -343,10 +343,10 @@ impl ByteMessageInfo { /// unconditional view of the raw field, this method refuses to hand /// back a value under the interpretation `op` says does not apply. /// - /// The polarity is TC18 §11.2.1 Table 4's own (TC18.txt line 1163): "if + /// The polarity is TC18 §11.2.1 Table 4's own (TC18.txt line 1235): "if /// op = 0 this is read_size, else segment_num", with `op = 0b` /// meaning "the sender of this request expects a response with data" - /// and `op = 1b` meaning it does not (TC18.txt lines 1160-1161). + /// and `op = 1b` meaning it does not (TC18.txt lines 1229-1230). //fusa:req REQ-BMI-005 //fusa:req REQ-ABB-009 pub fn read_size(&self) -> Option { @@ -375,7 +375,7 @@ impl ByteMessageInfo { } } - /// Classify this header under TC18 §11.3 Table 15/§11.3.1-§11.3.4's + /// Classify this header under TC18 §11.3 Table 17/§11.3.1-§11.3.4's /// response-direction reading of `evt` — the whole-nibble split /// [`Evt`]'s own doc comment says its `ack`+`sub_opcode` fields do /// *not* model. Meaningless for a request header, whose `evt` carries @@ -401,11 +401,11 @@ impl ByteMessageInfo { } } -/// TC18 §11.3 Table 15's `evt[3:0] == 0xF` response-kind marker -/// (TC18.txt line 1876: "evt[3:0] = 0xF - acknowledge"). +/// TC18 §11.3 Table 17's `evt[3:0] == 0xF` response-kind marker +/// (TC18.txt line 2255: "evt[3:0] = 0xF - acknowledge"). pub const EVT_RESPONSE_ACKNOWLEDGE: u8 = 0x0F; -/// The four response semantics TC18 §11.3 Table 15/§11.3.1-§11.3.4 define +/// The four response semantics TC18 §11.3 Table 17/§11.3.1-§11.3.4 define /// for a decoded [`ByteMessageInfo`] whose `rsp` bit is set. See /// [`ByteMessageInfo::response_kind`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -452,8 +452,8 @@ impl ResponseKind { /// 12 bits). /// /// Both `rsv` bit-pairs are always transmitted as zero, per TC18 §11.2.1 -/// Table 4 (TC18.txt line 1153, "rsv 00b") and TC18 §11.3 Table 15 -/// (TC18.txt line 1867, "rsv 00b"). They are not modeled as +/// Table 4 (TC18.txt line 1223, "rsv 00b") and TC18 §11.3 Table 17 +/// (TC18.txt line 2248, "rsv 00b"). They are not modeled as /// [`ByteMessageInfo`] fields at all, so there is no way for a caller to /// set them to anything else. //fusa:req REQ-BMI-002 @@ -564,9 +564,9 @@ pub fn decode_byte_message_info(b: &[u8]) -> Result { /// `acf_msg_type` discriminant identifying an ACF_ABB message. /// -/// TC18 §11.2.1 Table 4 (TC18.txt line 1149) fixes this at `0x0E` for a +/// TC18 §11.2.1 Table 4 (TC18.txt line 1219) fixes this at `0x0E` for a /// standard request ("acf_msg_type 0x0E (ABB message)"), and TC18 §11.3 -/// Table 15 (TC18.txt line 1863) repeats it for responses, spelling out +/// Table 17 (TC18.txt line 2242) repeats it for responses, spelling out /// what the value means: "0x0E - ABB message without message_timestamp". //fusa:req REQ-ABB-006 //fusa:req REQ-GBB-007 @@ -574,7 +574,7 @@ pub const ACF_ABB_MSG_TYPE: u8 = 0x0E; /// `acf_msg_type` discriminant identifying an ACF_GBB message. /// -/// TC18 §11.3 Table 15 (TC18.txt line 1863): "0x0D - GBB message, with +/// TC18 §11.3 Table 17 (TC18.txt line 2243): "0x0D - GBB message, with /// message_timestamp". The one structural difference the two discriminants /// name is exactly the 8-octet `message_timestamp`, which is why /// [`ACF_GBB_HEADER_LEN`] - [`ACF_ABB_HEADER_LEN`] is 8. @@ -610,6 +610,26 @@ pub const ACF_GBB_HEADER_LEN: usize = BYTE_MESSAGE_INFO_LEN + 8; // (as both worked examples do), it supplies those trailer bytes as part of // `payload` itself — this module has no separate CRC-trailer field of its // own (CRC computation itself lives in `crate::e2e`). +// +// TC18.txt citation-drift note (issue #164 batch 1): the current TC18.txt +// revision renumbers and re-paginates these two worked examples as Figure +// 20 ("ACF_ABB under TSCF header (example)", caption at TC18.txt line +// 4231) and Figure 21 ("ACF_GBB under NTSCF header (example)", caption at +// line ~4256) rather than Figure 19/Figure 20. The ACF_ABB example's own +// numbers (6 payload + 2 pad + 4-byte CRC32 = 20 bytes = 5 quadlets) are +// confirmed unchanged under its new Figure 20 label. The ACF_GBB example +// now shows a *different* split of the same 28-byte/7-quadlet total (5 +// payload + 3 pad, CRC32 still 4 bytes split 3+1 across quadlets, vs. the +// 7 payload + 1 pad this comment states) — TC18.txt carries a `Commented +// [BE39]: 051RC4 - text and figure updated` marker immediately after it, +// so this is a genuine content revision, not just a renumbering. The +// `acf_msg_length = 0x07` total this crate's logic actually depends on is +// unaffected either way. This module's own doc comments and +// `crate::e2e`'s `finalize_crc_trailer_matches_figure_19_worked_example`/ +// `_figure_20_worked_example` test names deliberately still say "Figure +// 19"/"Figure 20" throughout — renumbering them is left for a follow-up +// that also renames those `crate::e2e` test functions, rather than mixing +// old and new figure numbers across the two files. /// Number of bytes in one quadlet — the unit `acf_msg_length` counts in. pub const QUADLET_LEN: usize = 4; @@ -992,7 +1012,7 @@ pub fn verify_echo_back( /// number of the request. The error response shall contain a /// byte_msg_payload with an error code." /// -/// Returns `None` if `error` has no TC18 Table 27 wire code +/// Returns `None` if `error` has no TC18 Table 30 wire code /// ([`RcpError::tc18_wire_code`]) — there is no meaningful `err=1` response /// to build for an error TC18 itself does not name (e.g. a transport-level /// [`RcpError::Timeout`] or [`RcpError::ShortFrame`] from a frame this @@ -1006,7 +1026,7 @@ pub fn verify_echo_back( /// `byte_bus_id`/`transaction_num` are echoed from `request` (via /// [`build_response_info`], the same echo-back rule every other response /// in this crate uses), `rsp`/`err` are forced to `true`/`true`, and the -/// response payload is the single Table 27 error-code octet. TC18 does not +/// response payload is the single Table 30 error-code octet. TC18 does not /// spell out `byte_msg_payload`'s exact byte layout for an error response /// beyond "contains an error code" — this one-octet encoding is this /// crate's own working interpretation (Guiding Principle 5), matching the @@ -1015,19 +1035,19 @@ pub fn verify_echo_back( /// /// The returned message is always an [`AcfAbbMessage`] — i.e. the /// timestamp-free ACF_ABB format. That matches TC18 §11.3 (TC18.txt line -/// 1859: "In case responses include a timestamp, they are in ACF_GBB -/// format, else in ACF_ABB format") and §11.4.2 (TC18.txt line 1963: "When -/// timestamping was not requested, then the ACF_ABB type format without +/// 2239: "In case responses include a timestamp, they are in ACF_GBB +/// format, else in ACF_ABB format") and §11.4.2 (TC18.txt lines 2340-2341: +/// "When timestamping was not requested, then the ACF_ABB type format without /// time stamp shall be default for any data transmitted by the RC Server"), /// since this crate has no capture-timestamp source to put in a /// `message_timestamp` in the first place. /// -/// **Known gap.** TC18 §11.3.4 (TC18.txt line 1904) additionally requires an +/// **Known gap.** TC18 §11.3.4 (TC18.txt line 2300) additionally requires an /// error response to carry `evt[3:0] < 0x9`. This function copies /// `request`'s `evt` verbatim (via [`build_response_info`]), including /// `evt[3]` — TC18 §13.5's acknowledge-request bit — so an error response to /// a request that asked for an acknowledge can carry an `evt` nibble in -/// TC18 Table 15's reserved `0x9…0xE` range, or even `0xF`, which Table 15 +/// TC18 Table 17's reserved `0x9…0xE` range, or even `0xF`, which Table 17 /// defines as *acknowledge*. See requirement `REQ-RESP-007`. //fusa:req REQ-RESP-002 //fusa:req REQ-RESP-003 @@ -1246,7 +1266,7 @@ mod tests { } } - // ── response_kind (TC18 §11.3 Table 15) ───────────────────────────────── + // ── response_kind (TC18 §11.3 Table 17) ───────────────────────────────── #[test] //fusa:test REQ-RESP-004 @@ -2037,17 +2057,17 @@ mod tests { #[test] //fusa:test REQ-RESP-002 fn build_error_response_is_always_the_timestamp_free_abb_format() { - // TC18 §11.3 (TC18.txt line 1859): "In case responses include a + // TC18 §11.3 (TC18.txt line 2239): "In case responses include a // timestamp, they are in ACF_GBB format, else in ACF_ABB format." - // TC18 §11.4.2 (line 1963): "When timestamping was not requested, + // TC18 §11.4.2 (lines 2340-2341): "When timestamping was not requested, // then the ACF_ABB type format without time stamp shall be default // for any data transmitted by the RC Server." // - // The encoded response's `acf_msg_type` must therefore be Table 15's + // The encoded response's `acf_msg_type` must therefore be Table 17's // literal 0x0E ("ABB message without message_timestamp"), never // 0x0D ("GBB message, with message_timestamp"), and the encoded // message must be exactly 8 octets shorter than the same payload - // would occupy in GBB form (Table 15's only structural difference). + // would occupy in GBB form (Table 17's only structural difference). let request = sample_info(); for error in [ RcpError::UnsupportedCmd, @@ -2057,7 +2077,7 @@ mod tests { let response = build_error_response(&request, &error).unwrap(); let frame = encode_acf_abb(&response).unwrap(); let info = decode_byte_message_info(&frame[..BYTE_MESSAGE_INFO_LEN]).unwrap(); - assert_eq!(info.acf_msg_type, 0x0E, "Table 15 ABB discriminant"); + assert_eq!(info.acf_msg_type, 0x0E, "Table 17 ABB discriminant"); assert_ne!(info.acf_msg_type, 0x0D, "must not be the GBB form"); let gbb_equivalent = encode_acf_gbb(&AcfGbbMessage { @@ -2074,12 +2094,12 @@ mod tests { } } - // ── TC18 §11.2.1 Table 4 / §11.3 Table 15 literal field values ───────── + // ── TC18 §11.2.1 Table 4 / §11.3 Table 17 literal field values ───────── #[test] //fusa:test REQ-ABB-006 fn abb_standard_request_msg_type_matches_table_4_literal_and_bit_position() { - // TC18 §11.2.1 Table 4 (TC18.txt line 1149): "acf_msg_type + // TC18 §11.2.1 Table 4 (TC18.txt line 1219): "acf_msg_type // 0x0E (ABB message)". Per this module's canonical wire layout, // acf_msg_type occupies octet 0 bits 7:1, with acf_msg_length's MSB // in bit 0 — so for any message whose acf_msg_length fits in 8 bits, @@ -2103,10 +2123,12 @@ mod tests { #[test] //fusa:test REQ-GBB-007 fn table_15_discriminants_differ_by_exactly_the_message_timestamp() { - // TC18 §11.3 Table 15 (TC18.txt line 1863): + // TC18 §11.3 Table 17 (TC18.txt lines 2242-2243) [function name + // retained from this table's earlier "Table 15" numbering — see + // this file's citation-drift fix notes]: // acf_msg_type 0x0E - ABB message without message_timestamp // 0x0D - GBB message, with message_timestamp - // The message_timestamp is a 64-bit field (TC18 §11.4.1, line 1955: + // The message_timestamp is a 64-bit field (TC18 §11.4.1, line 2331: // "message_timestamp = ... mod 2^64"), i.e. 8 octets. assert_eq!(ACF_ABB_MSG_TYPE, 0x0E); assert_eq!(ACF_GBB_MSG_TYPE, 0x0D); @@ -2137,8 +2159,8 @@ mod tests { #[test] //fusa:test REQ-ABB-007 fn both_reserved_bit_pairs_are_always_transmitted_as_zero() { - // TC18 §11.2.1 Table 4 (TC18.txt line 1153) and §11.3 Table 15 - // (line 1867) both fix `rsv` at 00b. Per this module's canonical + // TC18 §11.2.1 Table 4 (TC18.txt line 1223) and §11.3 Table 17 + // (line 2248) both fix `rsv` at 00b. Per this module's canonical // wire layout the two rsv pairs are octet 2 bits 4:3 (mask 0x18) // and octet 4 bits 3:2 (mask 0x0C). Encoding every other field at // its own maximum must still leave both masks clear. @@ -2169,9 +2191,9 @@ mod tests { #[test] //fusa:test REQ-ABB-009 fn table_4_op_polarity_selects_read_size_at_zero_and_segment_num_at_one() { - // TC18 §11.2.1 Table 4 (TC18.txt line 1163): "read_size/segment_num + // TC18 §11.2.1 Table 4 (TC18.txt line 1235): "read_size/segment_num // — if op = 0 this is read_size, else segment_num", with op = 0b - // meaning the sender expects a response with data (line 1160). + // meaning the sender expects a response with data (line 1229). let read_request = ByteMessageInfo { op: false, read_size_segment: ReadSizeOrSegment(0x123), @@ -2194,7 +2216,7 @@ mod tests { #[test] //fusa:test REQ-EVT-001 fn evt_bit_3_is_the_acknowledge_request_bit() { - // TC18 §13.5 (TC18.txt line 3673): "evt[3] is used to request an + // TC18 §13.5 (TC18.txt line 4072): "evt[3] is used to request an // acknowledge. I.e. evt[3]=1 requests acknowledge." // The evt nibble occupies octet 4 bits 7:4, so evt[3] is octet 4 // bit 7 — mask 0x80. @@ -2226,9 +2248,12 @@ mod tests { #[test] //fusa:test REQ-EVT-002 fn evt_bits_2_to_0_are_the_three_bit_payload_usage_sub_opcode() { - // TC18 §13.5 (TC18.txt line 3672): "event bits evt[2:0] are used to - // control the usage of the byte_msg_payload." Table 30's own rows - // range over 000b..=111b, i.e. exactly three bits. + // TC18 §13.5 (TC18.txt line 4071): "event bits evt[2:0] are used to + // control the usage of the byte_msg_payload." Table 33's own rows + // (the endpoint-specific evt-field table, TC18.txt line 4116) range + // over 000b..=111b, i.e. exactly three bits. (An earlier revision of + // this comment miscited this as "Table 30" — that number belongs to + // TC18's unrelated "Error codes in responses" table.) assert_eq!(EVT_SUB_OPCODE_MAX, 0x07); // evt[2:0] occupies octet 4 bits 6:4, so a sub_opcode of `n` with diff --git a/src/avtp.rs b/src/avtp.rs index 2ddbef5..5de29e3 100644 --- a/src/avtp.rs +++ b/src/avtp.rs @@ -122,6 +122,21 @@ //! no extractable text layer; the bit-boundary tick marks were read //! directly from a 600 dpi render of pages 22 and 79. //! +//! TC18.txt citation-drift note (issue #164 batch 1): the current TC18.txt +//! revision's own (text) figure captions renumber these two worked +//! examples as Figure 20 ("ACF_ABB under TSCF header (example)", TC18.txt +//! line 4231) and Figure 21 ("ACF_GBB under NTSCF header (example)", +//! TC18.txt line ~4256) rather than Figure 19/Figure 20 — see +//! `crate::acf`'s own "acf_msg_length quadlet semantics" doc section for +//! the same finding and a content-change caveat on the ACF_GBB example. +//! This module's own doc comments and its +//! `ntscf_header_matches_figure_20_worked_example`/ +//! `tscf_header_matches_figure_19_worked_example` test names deliberately +//! still say "Figure 19"/"Figure 20" throughout, matching each other and +//! `crate::acf`/`crate::e2e`'s own still-unrenamed test names — renumbering +//! is left for a follow-up that renames those test functions together, +//! rather than mixing old and new figure numbers across files. +//! //! Note the asymmetry, which is real and not a transcription slip: //! NTSCF's `ntscf_data_length` is an **11-bit** field packed into the //! first quadlet, while TSCF's `stream_data_length` is a **16-bit** field @@ -131,9 +146,11 @@ //! [`StreamId`]'s split — sender MAC in the upper 48 bits, locally-assigned //! unique-id suffix in the lower 16 bits — follows the widely used IEEE //! 1722 AVTP convention of that name (talker MAC high, per-talker stream -//! discriminant low), and is confirmed by TC18 v0.5.1_RC §12.6.1 Table 16 -//! ("Discovery request") and §12.6.2 Table 17 ("Discovery response"), -//! page 48, which both spell the field out as +//! discriminant low), and is confirmed by TC18 v0.5.1_RC §12.6.1 Table 18 +//! ("Discovery request") and §12.6.2 Table 19 ("Discovery response") +//! (TC18.txt lines 2758/2805 — table renumbered from Table 16/Table 17 +//! since this note was written; see issue #164), page 48, which both +//! spell the field out as //! `stream_id = streamMAC + unique_id` with `streamMAC: 6bytes` and //! `unique_id = 0x0000` (2 bytes) — MAC first, suffix second, in a 64-bit //! field. This was previously flagged under Guiding Principle 5 as an @@ -468,7 +485,7 @@ pub enum HeaderVariant { /// a subtype that is neither [`NTSCF_SUBTYPE`] nor [`TSCF_SUBTYPE`]. All /// other decode-rejection paths (short frame past the subtype byte, sv bit, /// ...) are delegated to [`decode_ntscf_header`]/[`decode_tscf_header`]. -/// TC18 §12.8.2 "Reception of frames" (TC18.txt line 3170) states the +/// TC18 §12.8.2 "Reception of frames" (TC18.txt line 3567) states the /// discard rule this function's `other =>` arm implements: "If neither a /// gPTP nor an IEEE1722 frame is found the received frame shall be /// discarded." Only the two subtypes RCP itself defines — NTSCF @@ -614,10 +631,10 @@ pub fn parse_stream_id(raw: u64) -> ([u8; 6], u16) { /// [`encode_ntscf_header`] itself enforces). /// This is also the only whole-frame composition entry point this crate /// has, and it always emits an NTSCF header — matching TC18 §11.1 -/// (TC18.txt line 1062: the NTSCF header "shall be used for RCP requests +/// (TC18.txt lines 1130-1131: the NTSCF header "shall be used for RCP requests /// which shall be executed as soon as possible or under request specific /// conditions as well as for responses and acknowledge") and §11.4.3 -/// (TC18.txt line 1988: "The RC Server always uses NTSCF header"). There is +/// (TC18.txt line 2354: "The RC Server always uses NTSCF header"). There is /// deliberately no `encode_tscf_frame` counterpart: [`encode_tscf_header`] /// exists for a client's own use and for round-trip testing, but nothing in /// this crate assembles a TSCF-headed frame. @@ -1442,7 +1459,7 @@ mod tests { #[test] //fusa:test REQ-NET-002 fn select_header_variant_discards_every_subtype_but_the_two_rcp_ones() { - // TC18 §12.8.2 (TC18.txt line 3170): "If neither a gPTP nor an + // TC18 §12.8.2 (TC18.txt line 3567): "If neither a gPTP nor an // IEEE1722 frame is found the received frame shall be discarded." // The only two AVTPDU subtypes RCP defines are TC18 §11.1 // Figure 5's TSCF `subtype(0x05)` and Figure 6's NTSCF @@ -1472,7 +1489,7 @@ mod tests { #[test] //fusa:test REQ-NTSCF-007 fn frame_composition_always_emits_the_server_side_ntscf_header() { - // TC18 §11.1 (TC18.txt line 1062) and §11.4.3 (line 1988): the RC + // TC18 §11.1 (TC18.txt line 1130) and §11.4.3 (line 2354): the RC // Server always uses the NTSCF header, and responses/acknowledges // are always carried under it. `encode_ntscf_frame` is this // crate's only whole-frame composition entry point, and its first diff --git a/src/can.rs b/src/can.rs index 54170cf..e91bc57 100644 --- a/src/can.rs +++ b/src/can.rs @@ -257,21 +257,23 @@ //! [`CanFunctionalConfig`] carries one [`FrameFormat`] field rather than //! being left empty. //! -//! ## `FrameFormat` wire encoding (confirmed against TC18 Table 54) +//! ## `FrameFormat` wire encoding (confirmed against TC18 Table 57) //! //! `ROADMAP.md`'s checklist bullet names the six [`FrameFormat`] variants by //! their standard CAN abbreviations but states no numeric byte value for any //! of them, so [`FrameFormat::to_u8`]/[`FrameFormat::from_u8`] originally //! assigned each variant a stable, sequential byte value (`0`..=`5`, //! declaration order) as this crate's own working choice. TC18 §13.7.11.3 -//! Table 54 (TC18.txt line 5447) has since been reconciled against that +//! Table 57 (TC18.txt lines 5863-5871) has since been reconciled against that //! mapping and confirms it exactly: `CBFF = 0`, `CEFF = 1`, `FBFF = 2`, //! `FEFF = 3`, `XL (classic physical layer) = 4`, `XL (new physical //! layer) = 5`, with `6` and `7` both Reserved. The two XL rows also settle //! what `ROADMAP.md`'s "XL-classical"/"XL-new" naming meant: which physical //! layer the XL frame uses, not two different XL frame shapes. -//! [`FrameFormat::from_u8`]'s rejection of `6`/`7` is therefore Table 54's -//! own Reserved rows, not merely an out-of-enum range check. +//! [`FrameFormat::from_u8`]'s rejection of `6`/`7` is therefore Table 57's +//! own Reserved rows, not merely an out-of-enum range check. (This table was +//! "Table 54" when this module was first written; TC18.txt now numbers it +//! Table 57 — see issue #164.) //! //! [`FrameFormat::is_extended_id`] additionally distinguishes the base //! (11-bit arbitration ID) vs. extended (29-bit arbitration ID) rows among @@ -288,12 +290,12 @@ //! Reconciling this module against TC18 §13.7.11 confirms three further //! behaviors and records four gaps. //! -//! Confirmed: TC18 §13.7.11.3 (TC18.txt line 5471) states "Sending remote +//! Confirmed: TC18 §13.7.11.3 (TC18.txt line 5887) states "Sending remote //! frames is not supported", matching this module's own "Data frames only" //! section below; the same line states "In case the CAN ID is 11bits, then //! it shall be right aligned in the CAN ID field", which //! [`CanDataFrame::encode`]'s big-endian [`CanDataFrame::id`] field -//! satisfies; and line 5443 plus line 5472 together give CAN XL's total +//! satisfies; and line 5859 plus line 5888 together give CAN XL's total //! "CAN data" field size as 2054 bytes — up to 2048 payload bytes plus the //! 6 additional ISO 11898-1 bytes (RRS, SDT, VCID, AF) — matching //! [`CAN_XL_MAX_PAYLOAD`] + [`CAN_XL_SUB_HEADER_LEN`]. @@ -301,24 +303,31 @@ //! Not implemented, and recorded as explicit not-implemented requirement //! entries rather than silently omitted: //! -//! - The exact request-payload bit layout of TC18 Figure 39 (line 5428), -//! which carries `FrameFormat` and the CAN ID together in the payload's -//! first 32-bit word. This module instead emits a full format-tag byte -//! followed by a 4-byte big-endian CAN ID (5 bytes), so a +//! - The exact request-payload bit layout of TC18 Figure 40 (TC18.txt line +//! 5852), which carries `FrameFormat` and the CAN ID together in the +//! payload's first 32-bit word. This module instead emits a full +//! format-tag byte followed by a 4-byte big-endian CAN ID (5 bytes), so a //! [`CanDataFrame::encode`] buffer is **not** byte-compatible with Figure -//! 39's own word layout; the figure's column rendering does not survive +//! 40's own word layout; the figure's column rendering does not survive //! text extraction, so the exact bit positions are not transcribed here. +//! (This was cited as "Figure 39" when this module was first written; +//! TC18.txt's current Figure 39 is LIN's request format, not CAN's — the +//! figure this note actually means is the same Figure 40 already cited +//! elsewhere in this module's doc comments. See issue #164.) //! - Naming the 6 XL bytes as RRS/SDT/VCID/AF — [`CanXlSubHeader`] keeps //! them opaque. //! - Segmentation of an over-long CAN XL payload via the `ms` and -//! `segment_num` fields (line 5444); [`CanXlCombinedPayload::assemble`] -//! takes caller-ordered segments and reads neither field. -//! - TC18 Table 53's functional-config register layout (§13.7.11.2, lines -//! 5363-5419: bit-time registers 1-3, TDCC, EP/FIFO status, acceptance -//! filters 1-4, receive filters 1-4) and the six configuration -//! capabilities §13.7.11.2 enumerates (lines 5351-5356) — see -//! [`CanFunctionalConfig`], which carries a [`FrameFormat`] and nothing -//! else. +//! `segment_num` fields (TC18.txt line 5860); +//! [`CanXlCombinedPayload::assemble`] takes caller-ordered segments and +//! reads neither field. +//! - TC18 Table 56's functional-config register layout (§13.7.11.2, +//! TC18.txt lines 5795-5834: bit-time registers 1-3, TDCC, EP/FIFO +//! status, acceptance filters 1-4, receive filters 1-4) and the six +//! configuration capabilities §13.7.11.2 enumerates (TC18.txt lines +//! 5767-5772) — see [`CanFunctionalConfig`], which carries a +//! [`FrameFormat`] and nothing else. (This table was "Table 53" when +//! this module was first written; TC18.txt now numbers it Table 56 — +//! see issue #164.) //! //! ## Provenance note: the CAN XL sub-header is carried opaque //! @@ -414,14 +423,14 @@ pub const CAN_FD_MAX_PAYLOAD: usize = 64; /// Maximum CAN XL payload in bytes, per `ROADMAP.md`'s own stated ceiling /// for this checklist bullet and confirmed by TC18 §13.7.11.3 (TC18.txt -/// line 5443): "For CAN XL this can be up to 2054 bytes (2048 + 6)". +/// line 5859): "For CAN XL this can be up to 2054 bytes (2048 + 6)". //fusa:req REQ-CAN-006 //fusa:req REQ-CAN-016 pub const CAN_XL_MAX_PAYLOAD: usize = 2048; /// CAN XL's sub-header length in bytes, per `ROADMAP.md`'s own stated /// ceiling for this checklist bullet and confirmed by TC18 §13.7.11.3 -/// (TC18.txt line 5472): the "CAN data" field includes 6 additional bytes +/// (TC18.txt line 5888): the "CAN data" field includes 6 additional bytes /// (RRS, SDT, VCID, AF — see ISO 11898-1) for either XL frame format. See /// [`CanXlSubHeader`]. //fusa:req REQ-CAN-006 @@ -475,8 +484,8 @@ pub enum FrameFormat { impl FrameFormat { /// Encode this frame format as its wire byte value, per TC18 §13.7.11.3 - /// Table 54 (TC18.txt line 5447). See this module's doc comment - /// "`FrameFormat` wire encoding (confirmed against TC18 Table 54)". + /// Table 57 (TC18.txt lines 5863-5871). See this module's doc comment + /// "`FrameFormat` wire encoding (confirmed against TC18 Table 57)". //fusa:req REQ-CAN-001 //fusa:req REQ-CAN-012 pub fn to_u8(self) -> u8 { @@ -486,8 +495,8 @@ impl FrameFormat { /// Decode a wire byte value into a [`FrameFormat`]. /// /// Returns `Err(RcpError::InvalidParameter)` for any byte outside - /// `0..=5` — `6` and `7` are Table 54's own two Reserved rows (TC18 - /// §13.7.11.3, TC18.txt line 5454), and no `FrameFormat` value wider + /// `0..=5` — `6` and `7` are Table 57's own two Reserved rows (TC18 + /// §13.7.11.3, TC18.txt lines 5870-5871), and no `FrameFormat` value wider /// than 3 bits exists. Never panics for any input. //fusa:req REQ-CAN-002 //fusa:req REQ-CAN-013 @@ -584,12 +593,12 @@ impl CanDataFrame { /// validation lives. Never panics. /// /// The big-endian `id` field right-aligns an 11-bit CAN ID within the - /// CAN ID field, as TC18 §13.7.11.3 (TC18.txt line 5471) requires: "In + /// CAN ID field, as TC18 §13.7.11.3 (TC18.txt line 5887) requires: "In /// case the CAN ID is 11bits, then it shall be right aligned in the CAN /// ID field." No remote-frame (RTR) indication is emitted anywhere in /// this encoding — the same line states remote frames are not supported. /// See this module's doc comment "TC18 reconciliation note (§13.7.11)" - /// for how this 5-byte form relates to Figure 39's own 32-bit word. + /// for how this 5-byte form relates to Figure 40's own 32-bit word. //fusa:req REQ-CAN-004 //fusa:req REQ-CAN-014 //fusa:req REQ-CAN-015 @@ -921,13 +930,16 @@ mod tests { } } - // ── TC18 Table 54: confirmed FrameFormat wire values ──────────────────── + // ── TC18 Table 57: confirmed FrameFormat wire values ──────────────────── + // (This table was "Table 54" when this module was first written; + // TC18.txt now numbers it Table 57. Function names below still say + // "table_54" — see issue #164.) #[test] //fusa:test REQ-CAN-012 fn frame_format_wire_values_match_tc18_table_54() { - // TC18 §13.7.11.3 Table 54 "can frame formats" (TC18.txt line 5447), - // transcribed row by row: + // TC18 §13.7.11.3 Table 57 "can frame formats" (TC18.txt lines + // 5863-5871), transcribed row by row: // CBFF -> 0 // CEFF -> 1 // FBFF -> 2 @@ -948,7 +960,7 @@ mod tests { assert_eq!(FrameFormat::from_u8(4), Ok(FrameFormat::XlClassical)); assert_eq!(FrameFormat::from_u8(5), Ok(FrameFormat::XlNew)); - // Table 54's rows 4 and 5 are the two physical-layer variants of the + // Table 57's rows 4 and 5 are the two physical-layer variants of the // same XL frame format, so both classify as XL and neither as FD. assert!(FrameFormat::from_u8(4).unwrap().is_xl()); assert!(FrameFormat::from_u8(5).unwrap().is_xl()); @@ -957,14 +969,14 @@ mod tests { #[test] //fusa:test REQ-CAN-013 fn frame_format_from_u8_rejects_table_54_reserved_rows_6_and_7() { - // TC18 §13.7.11.3 Table 54 (TC18.txt lines 5454-5455): FrameFormat 6 + // TC18 §13.7.11.3 Table 57 (TC18.txt lines 5870-5871): FrameFormat 6 // and 7 are both "Reserved" — the only two of the 3-bit field's eight // code points without an assigned frame format. for reserved in [6u8, 7] { assert_eq!( FrameFormat::from_u8(reserved), Err(RcpError::InvalidParameter), - "Table 54 row {reserved} is Reserved" + "Table 57 row {reserved} is Reserved" ); } } @@ -1049,7 +1061,7 @@ mod tests { #[test] //fusa:test REQ-CAN-014 fn can_data_frame_encode_right_aligns_an_11_bit_can_id() { - // TC18 §13.7.11.3 (TC18.txt line 5471): "In case the CAN ID is + // TC18 §13.7.11.3 (TC18.txt line 5887): "In case the CAN ID is // 11bits, then it shall be right aligned in the CAN ID field." // // 11-bit ID 0x123 in a 4-byte big-endian CAN ID field is @@ -1080,8 +1092,8 @@ mod tests { #[test] //fusa:test REQ-CAN-015 fn can_data_frame_encoding_carries_no_remote_frame_indication() { - // TC18 §13.7.11.3 (TC18.txt line 5471): "Sending remote frames is not - // supported." The encoded form is exactly one Table 54 format byte, + // TC18 §13.7.11.3 (TC18.txt line 5887): "Sending remote frames is not + // supported." The encoded form is exactly one Table 57 format byte, // four CAN ID bytes, and the data bytes — there is no RTR bit, byte, // or trailing flag anywhere in it, for any of the four data-frame // formats. @@ -1246,8 +1258,8 @@ mod tests { #[test] //fusa:test REQ-CAN-016 fn can_xl_can_data_field_totals_2054_bytes() { - // TC18 §13.7.11.3 (TC18.txt line 5443): "For CAN XL this can be up to - // 2054 bytes (2048 + 6, see below)", and line 5472: the "CAN data" + // TC18 §13.7.11.3 (TC18.txt line 5859): "For CAN XL this can be up to + // 2054 bytes (2048 + 6, see below)", and line 5888: the "CAN data" // field includes 6 additional bytes (RRS, SDT, VCID, AF — see // ISO 11898-1) for either XL frame format. assert_eq!(CAN_XL_SUB_HEADER_LEN + CAN_XL_MAX_PAYLOAD, 2054);