Skip to main content

leodos_protocols/transport/cfdp/pdu/file_directive/keepalive/
small.rs

1use crate::transport::cfdp::CfdpError;
2use crate::transport::cfdp::pdu::EntityId;
3use crate::transport::cfdp::pdu::Pdu;
4use crate::transport::cfdp::pdu::PduHeaderFixedPart;
5use crate::transport::cfdp::pdu::TransactionSeqNum;
6use crate::transport::cfdp::pdu::file_directive::DirectiveCode;
7use crate::transport::cfdp::pdu::file_directive::FileDirectivePdu;
8use crate::transport::cfdp::pdu::header::Direction;
9use crate::transport::cfdp::pdu::header::PduType;
10use crate::transport::cfdp::pdu::header::TransmissionMode;
11
12use bon::bon;
13use zerocopy::FromBytes;
14use zerocopy::Immutable;
15use zerocopy::IntoBytes;
16use zerocopy::KnownLayout;
17use zerocopy::Unaligned;
18use zerocopy::network_endian::U32;
19
20/// A zero-copy representation of a Keep Alive PDU for **small files**.
21///
22/// This struct's layout strictly follows the CCSDS specification (Table 5-13)
23/// for a transaction where the `Large File Flag` in the header is `0`.
24///
25/// ```text
26/// +------------------------------------+----------+------------------------------------+
27/// | Field Name                         | Size     | Notes                              |
28/// +------------------------------------+----------+------------------------------------+
29/// | Progress                           | 32 bits  | FSS field, 32-bit version.         |
30/// +------------------------------------+----------+------------------------------------+
31/// ```
32#[repr(C)]
33#[derive(Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
34pub struct KeepAlivePduSmall {
35    /// The 32-bit progress indicator (bytes received so far).
36    progress: U32,
37}
38
39impl KeepAlivePduSmall {
40    /// Get the progress field as a u32.
41    pub fn progress(&self) -> u32 {
42        self.progress.get()
43    }
44    /// Sets the progress field.
45    pub fn set_progress(&mut self, progress: u32) {
46        self.progress.set(progress);
47    }
48}
49
50#[bon]
51impl KeepAlivePduSmall {
52    /// Builds a new small-file Keep Alive PDU in the given buffer.
53    #[builder]
54    pub fn new<'a>(
55        buffer: &'a mut [u8],
56        source_entity_id: EntityId,
57        dest_entity_id: EntityId,
58        transaction_seq_num: TransactionSeqNum,
59        transmission_mode: TransmissionMode,
60        crc_flag: bool,
61        progress: u32,
62    ) -> Result<&'a mut Pdu, CfdpError> {
63        let data_field_len = (DirectiveCode::size() + size_of::<Self>()) as u16;
64
65        let header = PduHeaderFixedPart::builder()
66            .version(1)
67            .pdu_type(PduType::FileDirective)
68            .direction(Direction::TowardSender)
69            .tx_mode(transmission_mode)
70            .crc_flag(crc_flag)
71            .large_file_flag(false) // Small version
72            .data_field_len(data_field_len)
73            .seg_ctrl(false)
74            .seg_meta_flag(false)
75            .build()?;
76
77        let pdu = Pdu::builder()
78            .buffer(buffer)
79            .header_fixed(header)
80            .source_entity_id(source_entity_id)
81            .destination_entity_id(dest_entity_id)
82            .transaction_seq_num(transaction_seq_num)
83            .build()?;
84
85        let data_field = pdu.data_field_mut().unwrap();
86        let directive_pdu = FileDirectivePdu::mut_from_bytes(data_field).unwrap();
87        directive_pdu.set_directive_code(DirectiveCode::KeepAlive);
88
89        let keepalive_pdu = KeepAlivePduSmall::mut_from_bytes(&mut directive_pdu.rest).unwrap();
90        keepalive_pdu.set_progress(progress);
91
92        Ok(pdu)
93    }
94}