Skip to main content

mfsk_core/uvpacket/
message.rs

1// SPDX-License-Identifier: GPL-3.0-or-later
2//! `UvPacketRawMessage` — trait-required-only message codec.
3//!
4//! The new uvpacket bypasses [`MessageCodec`] entirely; encoding /
5//! decoding happens at the *frame* level in [`crate::uvpacket::tx`]
6//! and [`crate::uvpacket::rx`]. The [`Protocol`] trait nevertheless
7//! requires a [`MessageCodec`] associated type to keep generic
8//! pipeline / registry code honest.
9//!
10//! `UvPacketRawMessage` satisfies that requirement with a trivial
11//! passthrough that:
12//! - declares `PAYLOAD_BITS = 101` (= the K of `Ldpc240_101`)
13//! - returns `None` from `pack` (uvpacket TX does not go through
14//!   this codec)
15//! - returns the raw 101 info bits as a 13-byte `Vec<u8>` from
16//!   `unpack` (with the trailing 3 bits zero-padded to a byte
17//!   boundary)
18//! - accepts unconditionally in `verify_info` — frame-level CRC-16
19//!   is what catches corruption, not a per-LDPC-block CRC
20//!
21//! This codec is **not** intended to be invoked directly by user
22//! code. The public uvpacket API is byte-pipe — see
23//! [`crate::uvpacket::tx::encode`] and
24//! [`crate::uvpacket::rx::decode`].
25//!
26//! [`MessageCodec`]: crate::core::MessageCodec
27//! [`Protocol`]: crate::core::Protocol
28
29use crate::core::{DecodeContext, MessageCodec, MessageFields};
30
31/// Trivial passthrough [`MessageCodec`] for the uvpacket family.
32/// See module-level docs.
33#[derive(Copy, Clone, Debug, Default)]
34pub struct UvPacketRawMessage;
35
36impl MessageCodec for UvPacketRawMessage {
37    type Unpacked = Vec<u8>;
38
39    /// Equal to `<Ldpc240_101 as FecCodec>::K`. The FEC produces 101
40    /// info bits per LDPC block; this codec exposes those bits as
41    /// raw bytes with the trailing 3 bits zero-padded to a byte
42    /// boundary.
43    const PAYLOAD_BITS: u32 = 101;
44
45    /// No per-block CRC — the frame-level CRC-16 (in
46    /// [`crate::uvpacket::framing`]) carries the integrity field.
47    const CRC_BITS: u32 = 0;
48
49    fn pack(&self, _fields: &MessageFields) -> Option<Vec<u8>> {
50        // Bypass: callers should encode at the frame level, not the
51        // message level. Returning `None` makes accidental misuse
52        // visible at the call site.
53        None
54    }
55
56    fn unpack(&self, info: &[u8], _ctx: &DecodeContext) -> Option<Self::Unpacked> {
57        if info.len() != Self::PAYLOAD_BITS as usize {
58            return None;
59        }
60        let n_bytes = info.len().div_ceil(8);
61        let mut out = vec![0u8; n_bytes];
62        for (i, &bit) in info.iter().enumerate() {
63            if bit != 0 {
64                out[i / 8] |= 1 << (7 - (i % 8));
65            }
66        }
67        Some(out)
68    }
69
70    fn verify_info(_info: &[u8]) -> bool {
71        // Per-block integrity is delegated to frame-level CRC-16.
72        true
73    }
74}