leodos_protocols/transport/cfdp/pdu/file_directive/nak/
small.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;
20
21#[repr(C)]
34#[derive(Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
35pub struct NakPduSmall {
36 start_of_scope: U32,
38 end_of_scope: U32,
40 rest: [u8],
42}
43
44impl NakPduSmall {
45 pub fn start_of_scope(&self) -> u32 {
47 self.start_of_scope.get()
48 }
49 pub fn set_start_of_scope(&mut self, scope: u32) {
51 self.start_of_scope.set(scope);
52 }
53
54 pub fn end_of_scope(&self) -> u32 {
56 self.end_of_scope.get()
57 }
58 pub fn set_end_of_scope(&mut self, scope: u32) {
60 self.end_of_scope.set(scope);
61 }
62
63 pub fn rest(&self) -> &[u8] {
65 &self.rest
66 }
67
68 pub fn segment_requests(&self) -> Result<&[NakSegmentSmall], CfdpError> {
70 <[NakSegmentSmall]>::ref_from_bytes(&self.rest)
71 .map_err(|_| CfdpError::Custom("Invalid NAK segment requests"))
72 }
73}
74
75#[repr(C)]
78#[derive(Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
79pub struct NakSegmentSmall {
80 start_offset: U32,
82 end_offset: U32,
84}
85
86impl NakSegmentSmall {
87 pub fn start_offset(&self) -> u32 {
89 self.start_offset.get()
90 }
91 pub fn set_start_offset(&mut self, offset: u32) {
93 self.start_offset.set(offset);
94 }
95
96 pub fn end_offset(&self) -> u32 {
98 self.end_offset.get()
99 }
100 pub fn set_end_offset(&mut self, offset: u32) {
102 self.end_offset.set(offset);
103 }
104}
105
106#[bon]
107impl NakPduSmall {
108 #[builder]
110 pub fn new<'a>(
111 buffer: &'a mut [u8],
112 source_entity_id: EntityId,
113 dest_entity_id: EntityId,
114 transaction_seq_num: TransactionSeqNum,
115 transmission_mode: TransmissionMode,
116 crc_flag: bool,
117 start_of_scope: u32,
118 end_of_scope: u32,
119 segment_requests: &'a [NakSegmentRequest],
120 ) -> Result<&'a mut Pdu, CfdpError> {
121 let fixed_part_len = size_of::<U32>() * 2;
122 let segments_len = segment_requests.len() * size_of::<NakSegmentSmall>();
123 let specific_data_len = fixed_part_len + segments_len;
124 let data_field_len = (1 + specific_data_len) as u16;
125
126 let header = PduHeaderFixedPart::builder()
127 .version(1)
128 .pdu_type(PduType::FileDirective)
129 .direction(Direction::TowardSender)
130 .tx_mode(transmission_mode)
131 .crc_flag(crc_flag)
132 .large_file_flag(false) .data_field_len(data_field_len)
134 .seg_ctrl(false)
135 .seg_meta_flag(false)
136 .build()?;
137
138 let pdu = Pdu::builder()
139 .buffer(buffer)
140 .header_fixed(header)
141 .source_entity_id(source_entity_id)
142 .destination_entity_id(dest_entity_id)
143 .transaction_seq_num(transaction_seq_num)
144 .build()?;
145
146 let data_field = pdu.data_field_mut().or_else(|_| {
147 Err(CfdpError::Custom(
148 "Failed to get mutable data field for NAK PDU",
149 ))
150 })?;
151 let directive_pdu = FileDirectivePdu::mut_from_bytes(data_field).or_else(|_| {
152 Err(CfdpError::Custom(
153 "Failed to get mutable directive PDU for NAK PDU",
154 ))
155 })?;
156 directive_pdu.set_directive_code(DirectiveCode::Nak);
157
158 let nak_pdu =
159 NakPduSmall::mut_from_bytes_with_elems(&mut directive_pdu.rest, segments_len)
160 .or_else(|_| Err(CfdpError::Custom("Failed to build NAK PDU")))?;
161 nak_pdu.set_start_of_scope(start_of_scope);
162 nak_pdu.set_end_of_scope(end_of_scope);
163
164 let segments_slice =
165 <[NakSegmentSmall]>::mut_from_bytes(&mut nak_pdu.rest).or_else(|_| {
166 Err(CfdpError::Custom(
167 "Failed to get mutable segment requests slice for NAK PDU",
168 ))
169 })?;
170 for (req, seg) in segment_requests.iter().zip(segments_slice.iter_mut()) {
171 if req.start_offset > u32::MAX as u64 || req.end_offset > u32::MAX as u64 {
172 return Err(CfdpError::DataTooLarge {
173 field: "segment offset",
174 max: u32::MAX as usize,
175 });
176 }
177 seg.set_start_offset(req.start_offset as u32);
178 seg.set_end_offset(req.end_offset as u32);
179 }
180
181 Ok(pdu)
182 }
183}