leodos_protocols/transport/srspp/
packet.rs1use crate::network::cfe::tc::TelecommandSecondaryHeader;
2use crate::network::isl::address::Address;
3use crate::network::isl::address::RawAddress;
4use crate::network::isl::routing::packet::IslRoutingTelecommandHeader;
5use crate::network::spp::Apid;
6use crate::network::spp::PacketType;
7use crate::network::spp::PacketVersion;
8use crate::network::spp::PrimaryHeader;
9use crate::network::spp::SecondaryHeaderFlag;
10use crate::network::spp::SequenceCount;
11use crate::network::spp::SequenceFlag;
12use crate::utils::checksum_u8;
13use crate::utils::get_bits_u8;
14use crate::utils::set_bits_u8;
15use crate::utils::validate_checksum_u8;
16use bon::bon;
17use core::mem::size_of;
18use zerocopy::FromBytes;
19use zerocopy::Immutable;
20use zerocopy::IntoBytes;
21use zerocopy::KnownLayout;
22use zerocopy::Unaligned;
23use zerocopy::byteorder::network_endian;
24
25pub const SRSPP_VERSION: u8 = 0;
28
29#[derive(Copy, Clone, Eq, PartialEq, Debug)]
31#[repr(u8)]
32pub enum SrsppType {
33 Data = 0,
35 Ack = 1,
37 Eos = 2,
39}
40
41impl TryFrom<u8> for SrsppType {
42 type Error = SrsppPacketError;
43
44 fn try_from(value: u8) -> Result<Self, Self::Error> {
45 match value {
46 0 => Ok(Self::Data),
47 1 => Ok(Self::Ack),
48 2 => Ok(Self::Eos),
49 _ => Err(SrsppPacketError::InvalidPacketType { value }),
50 }
51 }
52}
53
54#[repr(C, packed)]
60#[derive(FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable, Copy, Clone, Debug)]
61pub(crate) struct SrsppHeader {
62 source_address: RawAddress,
64 version_type: u8,
66}
67
68#[rustfmt::skip]
69mod bitmask {
70 pub const VERSION_MASK: u8 = 0b_1100_0000;
72 pub const TYPE_MASK: u8 = 0b_0011_0000;
74}
75
76impl SrsppHeader {
77 pub(crate) fn srspp_type(&self) -> Result<SrsppType, SrsppPacketError> {
79 SrsppType::try_from(get_bits_u8(self.version_type, bitmask::TYPE_MASK))
80 }
81
82 #[allow(unused)]
84 pub(crate) fn version(&self) -> u8 {
85 get_bits_u8(self.version_type, bitmask::VERSION_MASK)
86 }
87
88 pub(crate) fn source_address(&self) -> Address {
90 self.source_address.parse()
91 }
92
93 pub(crate) fn set_source_address(&mut self, address: Address) {
95 self.source_address = RawAddress::from(address);
96 }
97
98 pub(crate) fn set_srspp_type(&mut self, srspp_type: SrsppType) {
100 set_bits_u8(&mut self.version_type, bitmask::VERSION_MASK, SRSPP_VERSION);
101 set_bits_u8(&mut self.version_type, bitmask::TYPE_MASK, srspp_type as u8);
102 }
103}
104
105#[repr(C, packed)]
107#[derive(FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable, Copy, Clone, Debug)]
108pub struct AckPayload {
109 cumulative_ack: network_endian::U16,
111 selective_ack_bitmap: network_endian::U16,
113}
114
115impl AckPayload {
116 pub(crate) fn new(cumulative_ack: u16, bitmap: u16) -> Self {
118 Self {
119 cumulative_ack: network_endian::U16::new(cumulative_ack),
120 selective_ack_bitmap: network_endian::U16::new(bitmap),
121 }
122 }
123
124 #[allow(dead_code)]
128 pub(crate) fn cumulative_ack(&self) -> SequenceCount {
129 SequenceCount::from(self.cumulative_ack.get())
130 }
131
132 #[allow(dead_code)]
136 pub(crate) fn selective_ack_bitmap(&self) -> u16 {
137 self.selective_ack_bitmap.get()
138 }
139}
140
141#[repr(C, packed)]
143#[derive(FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable)]
144pub struct SrsppPacket {
145 pub primary: PrimaryHeader,
147 pub secondary: TelecommandSecondaryHeader,
149 pub(crate) isl_header: IslRoutingTelecommandHeader,
151 pub(crate) srspp_header: SrsppHeader,
153 pub rest: [u8],
155}
156
157impl SrsppPacket {
158 pub fn parse(bytes: &[u8]) -> Result<&Self, SrsppPacketError> {
160 Self::ref_from_bytes(bytes).map_err(|_| SrsppPacketError::BufferTooSmall {
161 required: SrsppDataPacket::HEADER_SIZE,
162 provided: bytes.len(),
163 })
164 }
165
166 pub fn srspp_type(&self) -> Result<SrsppType, SrsppPacketError> {
168 self.srspp_header.srspp_type()
169 }
170
171 pub fn source_address(&self) -> Address {
173 self.srspp_header.source_address()
174 }
175}
176
177#[repr(C, packed)]
187#[derive(FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable)]
188pub struct SrsppDataPacket {
189 pub primary: PrimaryHeader,
191 pub secondary: TelecommandSecondaryHeader,
193 pub(crate) isl_header: IslRoutingTelecommandHeader,
195 pub(crate) srspp_header: SrsppHeader,
197 pub payload: [u8],
199}
200
201impl SrsppDataPacket {
202 pub const HEADER_SIZE: usize = size_of::<PrimaryHeader>()
204 + size_of::<TelecommandSecondaryHeader>()
205 + size_of::<IslRoutingTelecommandHeader>()
206 + size_of::<SrsppHeader>();
207
208 pub fn parse(bytes: &[u8]) -> Result<&Self, SrsppPacketError> {
210 Self::ref_from_bytes(bytes).map_err(|_| SrsppPacketError::BufferTooSmall {
211 required: Self::HEADER_SIZE,
212 provided: bytes.len(),
213 })
214 }
215
216 pub const fn max_payload_size(mtu: usize) -> usize {
218 mtu.saturating_sub(Self::HEADER_SIZE)
219 }
220
221 pub fn set_cfe_checksum(&mut self) {
223 self.secondary.set_checksum(0);
224 self.secondary.set_checksum(checksum_u8(self.as_bytes()));
225 }
226
227 pub fn validate_cfe_checksum(&self) -> bool {
229 validate_checksum_u8(self.as_bytes())
230 }
231}
232
233#[repr(C, packed)]
243#[derive(FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable, Copy, Clone, Debug)]
244pub struct SrsppAckPacket {
245 pub primary: PrimaryHeader,
247 pub secondary: TelecommandSecondaryHeader,
249 pub(crate) isl_header: IslRoutingTelecommandHeader,
251 pub(crate) srspp_header: SrsppHeader,
253 pub(crate) ack_payload: AckPayload,
255}
256
257impl SrsppAckPacket {
258 pub fn parse(bytes: &[u8]) -> Result<&Self, SrsppPacketError> {
260 if bytes.len() < size_of::<Self>() {
261 return Err(SrsppPacketError::BufferTooSmall {
262 required: size_of::<Self>(),
263 provided: bytes.len(),
264 });
265 }
266 Self::ref_from_bytes(&bytes[..size_of::<Self>()]).map_err(|_| {
267 SrsppPacketError::BufferTooSmall {
268 required: size_of::<Self>(),
269 provided: bytes.len(),
270 }
271 })
272 }
273
274 pub fn set_cfe_checksum(&mut self) {
276 self.secondary.set_checksum(0);
277 self.secondary.set_checksum(checksum_u8(self.as_bytes()));
278 }
279
280 pub fn validate_cfe_checksum(&self) -> bool {
282 validate_checksum_u8(self.as_bytes())
283 }
284}
285
286#[derive(Debug, Copy, Clone, Eq, PartialEq, thiserror::Error)]
288pub enum SrsppPacketError {
289 #[error("buffer too small: required {required} bytes, provided {provided} bytes")]
291 BufferTooSmall {
292 required: usize,
294 provided: usize,
296 },
297 #[error("invalid SRSPP packet type: {value:#04x}")]
299 InvalidPacketType {
300 value: u8,
302 },
303 #[error("payload too large: maximum {max} bytes, provided {provided} bytes")]
305 PayloadTooLarge {
306 max: usize,
308 provided: usize,
310 },
311}
312
313#[bon]
314impl SrsppDataPacket {
315 #[builder]
317 pub fn new<'a>(
318 buffer: &'a mut [u8],
319 source_address: Address,
320 target: Address,
321 apid: Apid,
322 function_code: u8,
323 sequence_count: SequenceCount,
324 sequence_flag: SequenceFlag,
325 payload_len: usize,
326 ) -> Result<&'a mut SrsppDataPacket, SrsppPacketError> {
327 let required_len = Self::HEADER_SIZE + payload_len;
328 let provided_len = buffer.len();
329
330 let (packet, _) = SrsppDataPacket::mut_from_prefix_with_elems(buffer, payload_len)
331 .map_err(|_| SrsppPacketError::BufferTooSmall {
332 required: required_len,
333 provided: provided_len,
334 })?;
335
336 packet.primary.set_version(PacketVersion::VERSION_1);
337 packet.primary.set_packet_type(PacketType::Telecommand);
338 packet
339 .primary
340 .set_secondary_header_flag(SecondaryHeaderFlag::Present);
341 packet.primary.set_apid(apid);
342 packet.primary.set_sequence_count(sequence_count);
343 packet.primary.set_sequence_flag(sequence_flag);
344
345 let data_field_len = size_of::<TelecommandSecondaryHeader>()
346 + size_of::<IslRoutingTelecommandHeader>()
347 + size_of::<SrsppHeader>()
348 + payload_len;
349 packet.primary.set_data_field_len(data_field_len as u16);
350
351 packet.secondary.set_function_code(function_code);
352 packet.secondary.set_checksum(0);
353
354 packet.isl_header.set_target(target);
355
356 packet.srspp_header.set_source_address(source_address);
357 packet.srspp_header.set_srspp_type(SrsppType::Data);
358
359 packet.set_cfe_checksum();
360
361 Ok(packet)
362 }
363}
364
365#[bon]
366impl SrsppAckPacket {
367 #[builder]
369 pub fn new<'a>(
370 buffer: &'a mut [u8],
371 source_address: Address,
372 target: Address,
373 apid: Apid,
374 function_code: u8,
375 sequence_count: SequenceCount,
376 cumulative_ack: SequenceCount,
377 selective_bitmap: u16,
378 ) -> Result<&'a mut SrsppAckPacket, SrsppPacketError> {
379 let provided_len = buffer.len();
380 let (packet, _) = SrsppAckPacket::mut_from_prefix(buffer).map_err(|_| {
381 SrsppPacketError::BufferTooSmall {
382 required: size_of::<SrsppAckPacket>(),
383 provided: provided_len,
384 }
385 })?;
386
387 packet.primary.set_version(PacketVersion::VERSION_1);
388 packet.primary.set_packet_type(PacketType::Telecommand);
389 packet
390 .primary
391 .set_secondary_header_flag(SecondaryHeaderFlag::Present);
392 packet.primary.set_apid(apid);
393 packet.primary.set_sequence_count(sequence_count);
394 packet.primary.set_sequence_flag(SequenceFlag::Unsegmented);
395
396 let data_field_len = size_of::<TelecommandSecondaryHeader>()
397 + size_of::<IslRoutingTelecommandHeader>()
398 + size_of::<SrsppHeader>()
399 + size_of::<AckPayload>();
400 packet.primary.set_data_field_len(data_field_len as u16);
401
402 packet.secondary.set_function_code(function_code);
403 packet.secondary.set_checksum(0);
404
405 packet.isl_header.set_target(target);
406
407 packet.srspp_header.set_source_address(source_address);
408 packet.srspp_header.set_srspp_type(SrsppType::Ack);
409
410 packet.ack_payload = AckPayload::new(cumulative_ack.value(), selective_bitmap);
411
412 packet.set_cfe_checksum();
413
414 Ok(packet)
415 }
416}
417
418#[cfg(test)]
419mod tests {
420 use super::*;
421
422 fn source_address() -> Address {
423 Address::satellite(1, 5)
424 }
425
426 fn target_address() -> Address {
427 Address::satellite(2, 3)
428 }
429
430 #[test]
431 fn test_data_roundtrip() {
432 let mut buffer = [0u8; 256];
433 let apid = Apid::new(0x42).unwrap();
434 let payload_data = b"hello SRSPP";
435
436 let packet = SrsppDataPacket::builder()
437 .buffer(&mut buffer)
438 .source_address(source_address())
439 .target(target_address())
440 .apid(apid)
441 .function_code(0x10)
442 .sequence_count(SequenceCount::from(7))
443 .sequence_flag(SequenceFlag::Unsegmented)
444 .payload_len(payload_data.len())
445 .build()
446 .unwrap();
447
448 packet.payload.copy_from_slice(payload_data);
449 packet.set_cfe_checksum();
450
451 let bytes = packet.as_bytes();
452
453 let header = SrsppPacket::parse(bytes).unwrap();
454 assert_eq!(header.srspp_type().unwrap(), SrsppType::Data);
455
456 let parsed = SrsppDataPacket::parse(bytes).unwrap();
457 assert_eq!(parsed.primary.apid(), apid);
458 assert_eq!(parsed.primary.sequence_count().value(), 7);
459 assert_eq!(parsed.primary.packet_type(), PacketType::Telecommand);
460 assert_eq!(
461 parsed.primary.secondary_header_flag(),
462 SecondaryHeaderFlag::Present
463 );
464 assert_eq!(parsed.isl_header.target(), target_address());
465 assert_eq!(parsed.secondary.function_code(), 0x10);
466 assert_eq!(parsed.srspp_header.source_address(), source_address());
467 assert_eq!(&parsed.payload, payload_data);
468 assert!(parsed.validate_cfe_checksum());
469 }
470
471 #[test]
472 fn test_ack_roundtrip() {
473 let mut buffer = [0u8; 64];
474 let apid = Apid::new(0x42).unwrap();
475
476 let packet = SrsppAckPacket::builder()
477 .buffer(&mut buffer)
478 .source_address(source_address())
479 .target(target_address())
480 .apid(apid)
481 .function_code(0x10)
482 .sequence_count(SequenceCount::from(3))
483 .cumulative_ack(SequenceCount::from(15))
484 .selective_bitmap(0b1100)
485 .build()
486 .unwrap();
487
488 let bytes = packet.as_bytes();
489
490 let header = SrsppPacket::parse(bytes).unwrap();
491 assert_eq!(header.srspp_type().unwrap(), SrsppType::Ack);
492
493 let parsed = SrsppAckPacket::parse(bytes).unwrap();
494 assert_eq!(parsed.primary.apid(), apid);
495 assert_eq!(parsed.isl_header.target(), target_address());
496 assert_eq!(parsed.srspp_header.source_address(), source_address());
497 assert_eq!(parsed.ack_payload.cumulative_ack().value(), 15);
498 assert_eq!(parsed.ack_payload.selective_ack_bitmap(), 0b1100);
499 assert!(parsed.validate_cfe_checksum());
500 }
501
502 #[test]
503 fn test_parse_srspp_type() {
504 let mut buffer = [0u8; 128];
505 let apid = Apid::new(0x42).unwrap();
506
507 SrsppDataPacket::builder()
508 .buffer(&mut buffer)
509 .source_address(source_address())
510 .target(target_address())
511 .apid(apid)
512 .function_code(0)
513 .sequence_count(SequenceCount::from(0))
514 .sequence_flag(SequenceFlag::Unsegmented)
515 .payload_len(10)
516 .build()
517 .unwrap();
518
519 assert_eq!(
520 SrsppPacket::parse(&buffer).unwrap().srspp_type().unwrap(),
521 SrsppType::Data,
522 );
523
524 SrsppAckPacket::builder()
525 .buffer(&mut buffer)
526 .source_address(source_address())
527 .target(target_address())
528 .apid(apid)
529 .function_code(0)
530 .sequence_count(SequenceCount::from(0))
531 .cumulative_ack(SequenceCount::from(0))
532 .selective_bitmap(0)
533 .build()
534 .unwrap();
535
536 assert_eq!(
537 SrsppPacket::parse(&buffer).unwrap().srspp_type().unwrap(),
538 SrsppType::Ack,
539 );
540 }
541}