leodos_protocols/transport/cfdp/pdu/file_data/
with_meta.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::header::Direction;
7use crate::transport::cfdp::pdu::header::PduType;
8use crate::transport::cfdp::pdu::header::TransmissionMode;
9use crate::utils::get_bits_u8;
10use crate::utils::set_bits_u8;
11
12use bon::bon;
13use zerocopy::FromBytes;
14use zerocopy::Immutable;
15use zerocopy::IntoBytes;
16use zerocopy::KnownLayout;
17use zerocopy::Unaligned;
18use zerocopy::network_endian::U32;
19use zerocopy::network_endian::U64;
20
21#[repr(C)]
43#[derive(Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
44pub struct FileDataPduWithMeta {
45 admin_octet: u8,
47 rest: [u8],
49}
50
51#[rustfmt::skip]
52mod bitmasks {
54 pub const FILE_DATA_REC_CONT_STATE_MASK: u8 = 0b_11000000;
56 pub const FILE_DATA_SEG_META_LEN_MASK: u8 = 0b_00111111;
58}
59
60use bitmasks::*;
61
62impl FileDataPduWithMeta {
63 pub fn record_continuation_state(&self) -> u8 {
65 get_bits_u8(self.admin_octet, FILE_DATA_REC_CONT_STATE_MASK)
66 }
67 pub fn set_record_continuation_state(&mut self, state: u8) -> Result<(), CfdpError> {
69 if state > 0b11 {
70 return Err(CfdpError::DataTooLarge {
71 field: "record_continuation_state",
72 max: 3,
73 });
74 }
75 set_bits_u8(&mut self.admin_octet, FILE_DATA_REC_CONT_STATE_MASK, state);
76 Ok(())
77 }
78
79 pub fn metadata_len(&self) -> usize {
81 get_bits_u8(self.admin_octet, FILE_DATA_SEG_META_LEN_MASK) as usize
82 }
83 pub fn set_metadata_len(&mut self, len: u8) -> Result<(), CfdpError> {
85 if len > 63 {
86 return Err(CfdpError::DataTooLarge {
87 field: "segment_metadata_length",
88 max: 63,
89 });
90 }
91 set_bits_u8(&mut self.admin_octet, FILE_DATA_SEG_META_LEN_MASK, len);
92 Ok(())
93 }
94
95 pub fn segment_metadata(&self) -> Result<&[u8], CfdpError> {
97 self.rest
98 .get(0..self.metadata_len())
99 .ok_or_else(|| CfdpError::Custom("Invalid segment metadata slice"))
100 }
101 pub fn set_segment_metadata(&mut self, metadata: &[u8]) -> Result<(), CfdpError> {
103 let len = metadata.len();
104 if len > 63 {
105 return Err(CfdpError::DataTooLarge {
106 field: "segment_metadata",
107 max: 63,
108 });
109 }
110 let dest_slice = self
111 .rest
112 .get_mut(0..len)
113 .ok_or_else(|| CfdpError::Custom("Invalid segment metadata slice"))?;
114 dest_slice.copy_from_slice(metadata);
115 Ok(())
116 }
117
118 pub fn offset(&self, large_file_flag: bool) -> Result<u64, CfdpError> {
120 let offset_slice = self
121 .rest
122 .get(self.metadata_len()..)
123 .ok_or_else(|| CfdpError::Custom("Invalid FSS Offset slice"))?;
124 if large_file_flag {
125 U64::ref_from_prefix(offset_slice)
126 .map(|(len, _)| len.get())
127 .map_err(|_| CfdpError::Custom("Invalid FSS Offset"))
128 } else {
129 U32::ref_from_prefix(offset_slice)
130 .map(|(len, _)| len.get() as u64)
131 .map_err(|_| CfdpError::Custom("Invalid FSS Offset"))
132 }
133 }
134 pub fn set_offset(&mut self, offset: u64, large_file_flag: bool) -> Result<(), CfdpError> {
136 let offset_slice = self
137 .rest
138 .get_mut(self.metadata_len()..)
139 .ok_or_else(|| CfdpError::Custom("Invalid FSS Offset slice"))?;
140 if large_file_flag {
141 U64::mut_from_prefix(offset_slice)
142 .map(|(len, _)| len.set(offset))
143 .map_err(|_| CfdpError::Custom("Invalid FSS Offset"))
144 } else {
145 if offset > u32::MAX as u64 {
146 return Err(CfdpError::DataTooLarge {
147 field: "offset",
148 max: u32::MAX as usize,
149 });
150 }
151 U32::mut_from_prefix(offset_slice)
152 .map(|(len, _)| len.set(offset as u32))
153 .map_err(|_| CfdpError::Custom("Invalid FSS Offset"))
154 }
155 }
156
157 pub fn file_data<'a>(&'a self, large_file_flag: bool) -> Result<&'a [u8], CfdpError> {
159 let offset_len = if large_file_flag { 8 } else { 4 };
160 let start = self.metadata_len() + offset_len;
161 self.rest
162 .get(start..)
163 .ok_or_else(|| CfdpError::Custom("Invalid file data slice"))
164 }
165 pub fn file_data_mut(&mut self, large_file_flag: bool) -> Result<&mut [u8], CfdpError> {
167 let offset_len = if large_file_flag { 8 } else { 4 };
168 let start = self.metadata_len() + offset_len;
169 self.rest
170 .get_mut(start..)
171 .ok_or_else(|| CfdpError::Custom("Invalid file data slice"))
172 }
173
174 pub fn admin_octet(&self) -> u8 {
176 self.admin_octet
177 }
178
179 pub fn rest(&self) -> &[u8] {
181 &self.rest
182 }
183}
184
185#[bon]
186impl FileDataPduWithMeta {
187 #[builder]
190 pub fn new<'a>(
191 buffer: &'a mut [u8],
192 source_entity_id: EntityId,
194 destination_entity_id: EntityId,
195 transaction_seq_num: TransactionSeqNum,
196 transmission_mode: TransmissionMode,
197 large_file_flag: bool,
198 crc_flag: bool,
199 segmentation_control: bool,
201 record_continuation_state: u8,
202 segment_metadata: &'a [u8],
203 offset: u64,
204 file_data_len: usize,
205 ) -> Result<&'a mut Pdu, CfdpError> {
206 if record_continuation_state > 0b11 {
207 return Err(CfdpError::DataTooLarge {
208 field: "record_continuation_state",
209 max: 3,
210 });
211 }
212 if segment_metadata.len() > 63 {
213 return Err(CfdpError::DataTooLarge {
214 field: "segment_metadata",
215 max: 63,
216 });
217 }
218
219 let fixed_part_len = size_of::<u8>();
220 let metadata_len = segment_metadata.len();
221 let offset_len = if large_file_flag { 8 } else { 4 };
222 let data_field_len = (fixed_part_len + metadata_len + offset_len + file_data_len) as u16;
223
224 let header = PduHeaderFixedPart::builder()
225 .version(1)
226 .pdu_type(PduType::FileData)
227 .direction(Direction::TowardReceiver)
228 .tx_mode(transmission_mode)
229 .crc_flag(crc_flag)
230 .large_file_flag(large_file_flag)
231 .data_field_len(data_field_len)
232 .seg_ctrl(segmentation_control)
233 .seg_meta_flag(true) .build()?;
235
236 let pdu = Pdu::builder()
237 .buffer(buffer)
238 .header_fixed(header)
239 .source_entity_id(source_entity_id)
240 .destination_entity_id(destination_entity_id)
241 .transaction_seq_num(transaction_seq_num)
242 .build()?;
243
244 let data_field = pdu.data_field_mut().unwrap();
245 let fd_pdu = FileDataPduWithMeta::mut_from_bytes(data_field).unwrap();
246
247 fd_pdu.set_record_continuation_state(record_continuation_state)?;
248 fd_pdu.set_metadata_len(segment_metadata.len() as u8)?;
249 fd_pdu.set_segment_metadata(segment_metadata)?;
250 fd_pdu.set_offset(offset, large_file_flag)?;
251 Ok(pdu)
252 }
253}