leodos_protocols/transport/cfdp/pdu/file_directive/nak/
large.rs1use 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::file_directive::nak::NakSegmentRequest;
9use crate::transport::cfdp::pdu::header::Direction;
10use crate::transport::cfdp::pdu::header::PduType;
11use crate::transport::cfdp::pdu::header::TransmissionMode;
12
13use bon::bon;
14use zerocopy::FromBytes;
15use zerocopy::Immutable;
16use zerocopy::IntoBytes;
17use zerocopy::KnownLayout;
18use zerocopy::Unaligned;
19use zerocopy::network_endian::U32;
20use zerocopy::network_endian::U64;
21
22#[repr(C)]
35#[derive(Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
36pub struct NakPduLarge {
37 start_of_scope: U64,
39 end_of_scope: U64,
41 rest: [u8],
43}
44
45impl NakPduLarge {
46 pub fn segment_requests(&self) -> Result<&[NakSegmentLarge], CfdpError> {
48 <[NakSegmentLarge]>::ref_from_bytes(&self.rest)
49 .map_err(|_| CfdpError::Custom("Invalid NAK segment requests"))
50 }
51
52 pub fn start_of_scope(&self) -> u64 {
54 self.start_of_scope.get()
55 }
56 pub fn set_start_of_scope(&mut self, scope: u64) {
58 self.start_of_scope.set(scope);
59 }
60
61 pub fn end_of_scope(&self) -> u64 {
63 self.end_of_scope.get()
64 }
65 pub fn set_end_of_scope(&mut self, scope: u64) {
67 self.end_of_scope.set(scope);
68 }
69
70 pub fn rest(&self) -> &[u8] {
72 &self.rest
73 }
74}
75
76#[repr(C)]
79#[derive(Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
80pub struct NakSegmentLarge {
81 start_offset: U64,
83 end_offset: U64,
85}
86
87impl NakSegmentLarge {
88 pub fn start_offset(&self) -> u64 {
90 self.start_offset.get()
91 }
92 pub fn set_start_offset(&mut self, offset: u64) {
94 self.start_offset.set(offset);
95 }
96
97 pub fn end_offset(&self) -> u64 {
99 self.end_offset.get()
100 }
101 pub fn set_end_offset(&mut self, offset: u64) {
103 self.end_offset.set(offset);
104 }
105}
106
107#[bon]
108impl NakPduLarge {
109 #[builder]
111 pub fn new<'a>(
112 buffer: &'a mut [u8],
113 source_entity_id: EntityId,
114 dest_entity_id: EntityId,
115 transaction_seq_num: TransactionSeqNum,
116 transmission_mode: TransmissionMode,
117 crc_flag: bool,
118 start_of_scope: u64,
119 end_of_scope: u64,
120 segment_requests: &'a [NakSegmentRequest],
121 ) -> Result<&'a mut Pdu, CfdpError> {
122 let fixed_part_len = size_of::<U32>() * 2;
123 let segments_len = segment_requests.len() * size_of::<NakSegmentLarge>();
124 let specific_data_len = fixed_part_len + segments_len;
125 let data_field_len = (1 + specific_data_len) as u16;
126
127 let header = PduHeaderFixedPart::builder()
128 .version(1)
129 .pdu_type(PduType::FileDirective)
130 .direction(Direction::TowardSender)
131 .tx_mode(transmission_mode)
132 .crc_flag(crc_flag)
133 .large_file_flag(true)
134 .data_field_len(data_field_len)
135 .seg_ctrl(false)
136 .seg_meta_flag(false)
137 .build()?;
138
139 let pdu = Pdu::builder()
140 .buffer(buffer)
141 .header_fixed(header)
142 .source_entity_id(source_entity_id)
143 .destination_entity_id(dest_entity_id)
144 .transaction_seq_num(transaction_seq_num)
145 .build()?;
146
147 let data_field = pdu.data_field_mut().or_else(|_| {
148 Err(CfdpError::Custom(
149 "Failed to get mutable data field for NAK PDU",
150 ))
151 })?;
152 let directive_pdu = FileDirectivePdu::mut_from_bytes(data_field).or_else(|_| {
153 Err(CfdpError::Custom(
154 "Failed to get mutable directive PDU for NAK PDU",
155 ))
156 })?;
157 directive_pdu.set_directive_code(DirectiveCode::Nak);
158
159 let nak_pdu =
160 NakPduLarge::mut_from_bytes_with_elems(&mut directive_pdu.rest, segments_len)
161 .or_else(|_| Err(CfdpError::Custom("Failed to build NAK PDU")))?;
162 nak_pdu.set_start_of_scope(start_of_scope);
163 nak_pdu.set_end_of_scope(end_of_scope);
164
165 let segments_slice =
166 <[NakSegmentLarge]>::mut_from_bytes(&mut nak_pdu.rest).or_else(|_| {
167 Err(CfdpError::Custom(
168 "Failed to get mutable segment requests slice for NAK PDU",
169 ))
170 })?;
171 for (req, seg) in segment_requests.iter().zip(segments_slice.iter_mut()) {
172 seg.set_start_offset(req.start_offset);
173 seg.set_end_offset(req.end_offset);
174 }
175
176 Ok(pdu)
177 }
178}