Skip to main content

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

1use bon::bon;
2use zerocopy::FromBytes;
3use zerocopy::Immutable;
4use zerocopy::IntoBytes;
5use zerocopy::KnownLayout;
6use zerocopy::Unaligned;
7use zerocopy::network_endian::U64;
8
9use crate::transport::cfdp::CfdpError;
10use crate::transport::cfdp::pdu::EntityId;
11use crate::transport::cfdp::pdu::Pdu;
12use crate::transport::cfdp::pdu::TransactionSeqNum;
13use crate::transport::cfdp::pdu::file_directive::DirectiveCode;
14use crate::transport::cfdp::pdu::file_directive::FileDirectivePdu;
15use crate::transport::cfdp::pdu::header::Direction;
16use crate::transport::cfdp::pdu::header::PduHeaderFixedPart;
17use crate::transport::cfdp::pdu::header::PduType;
18use crate::transport::cfdp::pdu::header::TransmissionMode;
19
20/// A zero-copy representation of a Keep Alive PDU for **large 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                           | 64 bits  | FSS field, 64-bit version.         |
30/// +------------------------------------+----------+------------------------------------+
31/// ```
32#[repr(C)]
33#[derive(Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
34pub struct KeepAlivePduLarge {
35    /// The 64-bit progress indicator (bytes received so far).
36    progress: U64,
37}
38
39impl KeepAlivePduLarge {
40    /// Get the progress field as a u64.
41    pub fn progress(&self) -> u64 {
42        self.progress.get()
43    }
44    /// Sets the progress field.
45    pub fn set_progress(&mut self, progress: u64) {
46        self.progress.set(progress);
47    }
48}
49
50#[bon]
51impl KeepAlivePduLarge {
52    /// Builds a new large-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: u64,
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(true)
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 = KeepAlivePduLarge::mut_from_bytes(&mut directive_pdu.rest).unwrap();
90        keepalive_pdu.set_progress(progress);
91
92        Ok(pdu)
93    }
94}