diff --git a/src/bits.rs b/src/bits.rs index f403bdf..5341f10 100644 --- a/src/bits.rs +++ b/src/bits.rs @@ -15,7 +15,7 @@ pub trait FromBytes: Sized /// A [`Parsed`] struct with the parsed value and bytes consumed, or an error. /// /// # Example - /// ``` + /// ```text /// ``` fn from_bytes(bytes: &[u8]) -> Result, Self::Error>; } @@ -108,3 +108,82 @@ impl Parsed } } } + + + +#[inline(always)] +pub fn update_masked_bits(value: &mut u8, mask: u8, new_data: u8) +{ + *value &= !mask; + *value |= new_data & mask; +} + + +/// Clears and sets masked bits within a mutable 2-byte array by calling +/// the core u8 function for each byte explicitly (loop unrolled). +#[inline(always)] +pub fn update_masked_bits_arr(value: &mut [u8; 2], mask: &[u8; 2], + new_data: &[u8; 2]) +{ + // 0: MSB (Most Significant Byte). + update_masked_bits(&mut value[0], mask[0], new_data[0]); + + // 1: LSB (Least Significant Byte). + update_masked_bits(&mut value[1], mask[1], new_data[1]); +} + + +/// Clears and sets masked bits within a mutable u16. +#[inline(always)] +pub fn update_masked_bits_u16(value: &mut u16, mask: u16, new_data: u16) +{ + // 1. Split u16s into Big-Endian (Network Byte Order) byte arrays. + let mut current_bytes: [u8; 2] = value.to_be_bytes(); + let mask_bytes: [u8; 2] = mask.to_be_bytes(); + let new_data_bytes: [u8; 2] = new_data.to_be_bytes(); + + // 2. Call the intermediate array function. + update_masked_bits_arr(&mut current_bytes, &mask_bytes, &new_data_bytes); + + // 3. Recombine the modified byte array back into the mutable u16 reference. + *value = u16::from_be_bytes(current_bytes); +} + + + +/// Checks if a buffer, or buffer and mask, meets a minimum required length. +/// +/// If the length is less than the minimum, it returns a +/// `PacketError::BufferTooSmall` or a `PacketError::MaskTooSmall`. +/// +/// # Usage +/// ```rust +/// check_buffer_len!(2, bytes, mask); +/// // Checks bytes.len() >= 2 AND mask.len() >= 2 +/// ``` +#[macro_export] +macro_rules! check_buffer_len +{ + // Single buffer. + ($min_len:expr, $buffer:expr) => + { + if $buffer.len() < $min_len + { + return Err($crate::error::PacketError::BufferTooSmall); + } + }; + + // Check buffer and mask simultaneously. + ($min_len:expr, $buffer:expr, $mask:expr) => + { + if $buffer.len() < $min_len + { + return Err($crate::error::PacketError::BufferTooSmall); + } + + if $mask.len() < $min_len + { + return Err($crate::error::PacketError::MaskTooSmall); + } + }; +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..3bb5f4f --- /dev/null +++ b/src/error.rs @@ -0,0 +1,69 @@ +use std::fmt; + + + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PacketError +{ + /// The provided buffer is smaller than the 6-byte header. + BufferTooSmall, + + /// The provided mask is smaller than the 6-byte header. + MaskTooSmall, + + /// The CCSDS version is not supported (should be 0). + InvalidVersion(u8), + + /// APID exceeds 11 bits (2047). + InvalidApId(u16), + + /// An Unknown PacketType was received. + InvalidPacketType(u8), + + /// . + InvalidSequenceFlag(u8), + + /// Tried to access secondary header but flag was not set. + NoSecondaryHeader, + + /// Secondary header length exceeds payload length. + SecondaryHeaderTooLong, + + /// The provided buffer is smaller than the length claimed by the packet header. + IncompletePacket { expected_len: usize, actual_len: usize }, + + /// Payload cannot be empty (CCSDS requires at least 1 octet). + EmptyPayload +} + + + +impl fmt::Display for PacketError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self + { + PacketError::BufferTooSmall => + write!(f, "Buffer too small for header"), + PacketError::MaskTooSmall => + write!(f, "Mask too small for header"), + PacketError::InvalidVersion(v) => + write!(f, "Invalid Version: {}", v), + PacketError::InvalidApId(id) => + write!(f, "APID {} exceeds 2047", id), + PacketError::InvalidPacketType(pt) => + write!(f, "Invalid Packet Type: {}", pt), + PacketError::InvalidSequenceFlag(flag) => + write!(f, "Invalid Packet Type: {}", flag), + PacketError::NoSecondaryHeader => + write!(f, "Secondary Header flag not set"), + PacketError::SecondaryHeaderTooLong => + write!(f, "Secondary Header length > Payload length"), + PacketError::IncompletePacket { expected_len, actual_len } => + write!(f, "Packet truncated: expected {} bytes, got {}", expected_len, actual_len), + PacketError::EmptyPayload => + write!(f, "Payload cannot be empty") + } + } +} diff --git a/src/header.rs b/src/header.rs deleted file mode 100644 index f7fe03b..0000000 --- a/src/header.rs +++ /dev/null @@ -1,392 +0,0 @@ -//! # Header -//! The -use crate::bits::*; - - - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ApId -{ - value: u16 -} - -impl ApId -{ - pub const MASK_U16: u16 = 0b0000011111111111; - pub const MASK_ARR: [u8; 2] = [0b00000111, 0b11111111]; -} - -impl From for ApId -{ - fn from(value: u16) -> Self - { - ApId - { - value - } - } -} - -impl From for u16 -{ - fn from(apid: ApId) -> u16 - { - apid.value - } -} - -impl FromBytes for ApId -{ - type Error = &'static str; - - fn from_bytes(bytes: &[u8]) -> Result, Self::Error> - { - if bytes.len() < 2usize { return Err("ERROR"); } - - let id: u16 = (((bytes[0] & ApId::MASK_ARR[0]) as u16) << 8) | - (((bytes[1] & ApId::MASK_ARR[1]) as u16)); - - Ok(Parsed::new(2usize, id.into())) - } -} - -impl IntoBytes for ApId -{ - type Error = &'static str; - - fn into_bytes(self, buffer: &mut [u8]) -> Result - { - if buffer.len() < 2usize { return Err("Error"); } - - let id: u16 = self.value; - - buffer[0] = ((id >> 8) as u8) & ApId::MASK_ARR[0]; - buffer[1] = (id as u8) & ApId::MASK_ARR[0]; - - Ok(2usize) - } -} - -impl FromBits for ApId -{ - type Error = &'static str; - - fn from_bits(bytes: &[u8], mask: &[u8]) -> Result - { - if bytes.len() < 2usize || mask.len() < 2usize { return Err("Error"); } - - let id: u16 = (((bytes[0] & mask[0]) as u16) << 8) | - ((bytes[1] & mask[1]) as u16); - - Ok(id.into()) - } -} - -impl IntoBits for ApId -{ - type Error = &'static str; - - fn into_bits(self, bytes: &mut [u8], mask: &[u8]) -> Result<(), Self::Error> - { - if bytes.len() < 2usize || mask.len() < 2usize { return Err("Error"); } - - let id: u16 = self.value; - - bytes[0] = ((id >> 8) as u8) & mask[0]; - bytes[1] = (id as u8) & mask[1]; - - Ok(()) - } -} - - - -pub enum Version -{ - One -} - -const VERSION_ONE: u8 = 0b00000000; -impl Version -{ - pub const MASK_U8: u8 = 0b11100000; - pub const MASK_ARR: [u8; 1] = [Version::MASK_U8]; -} - -impl FromBytes for Version -{ - type Error = &'static str; - - fn from_bytes(bytes: &[u8]) -> Result, Self::Error> - { - if bytes.len() < 1usize { return Err("ERROR"); } - - match bytes[0] & Version::MASK_U8 - { - VERSION_ONE => { Ok(Parsed::new(1usize, Version::One)) } - - _ => { Err("Error: Unknown Version") } - } - } -} - -impl IntoBytes for Version -{ - type Error = &'static str; - - fn into_bytes(self, buffer: &mut [u8]) -> Result - { - if buffer.len() < 1 { return Err("Error"); } - - match self - { - Version::One => { buffer[0] = VERSION_ONE; } - } - - Ok(1) - } -} - -impl FromBits for Version -{ - type Error = &'static str; - - fn from_bits(bytes: &[u8], mask: &[u8]) -> Result - { - if bytes.len() < 1 || mask.len() < 1 { return Err("Error"); } - - match bytes[0] & mask[0] - { - VERSION_ONE => { Ok(Version::One) } - - _ => { Err("ERROR") } - } - } -} - -impl IntoBits for Version -{ - type Error = &'static str; - - fn into_bits(self, bytes: &mut [u8], mask: &[u8]) -> Result<(), Self::Error> - { - if bytes.len() < 1 || mask.len() < 1 { return Err("Error"); } - - match self - { - Version::One => { bytes[0] |= VERSION_ONE & mask[0]; } - } - - Ok(()) - } -} - - - -pub enum PacketType -{ - Telemetry, - Telecommand -} - -const TYPE_TELEMETRY: u8 = 0b00000000; -const TYPE_TELECOMMAND: u8 = 0b00010000; - -impl PacketType -{ - pub const MASK_U8: u8 = 0b00010000; - pub const MASK_ARR: [u8; 1] = [PacketType::MASK_U8]; -} - -impl FromBytes for PacketType -{ - type Error = &'static str; - - fn from_bytes(bytes: &[u8]) -> Result, Self::Error> - { - if bytes.len() < 1usize { return Err("ERROR"); } - - match bytes[0] & PacketType::MASK_U8 - { - TYPE_TELEMETRY => { Ok(Parsed::new(1usize, PacketType::Telemetry)) } - TYPE_TELECOMMAND => { Ok(Parsed::new(1usize, PacketType::Telecommand)) } - - _ => { Err("Error: Unknown PacketType.") } - } - } -} - -impl IntoBytes for PacketType -{ - type Error = &'static str; - - fn into_bytes(self, buffer: &mut [u8]) -> Result - { - match self - { - PacketType::Telemetry => { buffer[0] = TYPE_TELEMETRY; } - PacketType::Telecommand => { buffer[0] = TYPE_TELECOMMAND; } - } - - Ok(1) - } -} - -impl FromBits for PacketType -{ - type Error = &'static str; - - fn from_bits(bytes: &[u8], mask: &[u8]) -> Result - { - if bytes.len() < 1 || mask.len() < 1 { return Err("Error"); } - - match bytes[0] & mask[0] - { - TYPE_TELEMETRY => { Ok(PacketType::Telemetry) } - TYPE_TELECOMMAND => { Ok(PacketType::Telecommand) } - - _ => { Err("ERROR") } - } - } -} - -impl IntoBits for PacketType -{ - type Error = &'static str; - - fn into_bits(self, bytes: &mut [u8], mask: &[u8]) -> Result<(), Self::Error> - { - if bytes.len() < 1 || mask.len() < 1 { return Err("Error"); } - - match self - { - PacketType::Telemetry => { bytes[0] |= TYPE_TELEMETRY & mask[0]; } - PacketType::Telecommand => { bytes[0] |= TYPE_TELECOMMAND & mask[0]; } - } - - Ok(()) - } -} - - - -const HEADER_SIZE: usize = 6usize; -pub struct PacketHeader -{ - data: [u8; HEADER_SIZE] -} - -impl PacketHeader -{ - pub fn get_version(&self) -> Version - { - match Version::from_bits(&self.data[0..1], &Version::MASK_ARR) - { - Ok(version) => - { - version - } - - Err(error) => - { - println!("Error: {}", error); - Version::One - } - } - } - - pub fn get_packet_type(&self) -> PacketType - { - match PacketType::from_bits(&self.data[0..1], &PacketType::MASK_ARR) - { - Ok(packet_type) => - { - packet_type - } - - Err(error) => - { - println!("Error: {}", error); - PacketType::Telemetry - } - } - } - - pub fn get_ap_id(&self) -> ApId - { - match ApId::from_bits(&self.data[0..2], &ApId::MASK_ARR) - { - Ok(id) => - { - id - } - - Err(error) => - { - println!("Error: {}", error); - 0.into() - } - } - } - - pub fn set_version(&mut self, version: Version) - { - match version.into_bits(&mut self.data[0..1], &Version::MASK_ARR) - { - Ok(_) => {} - - Err(error) => { println!("Error: {}", error); } - } - } - - pub fn set_packet_type(&mut self, packet_type: PacketType) - { - match packet_type.into_bits(&mut self.data[0..1], &PacketType::MASK_ARR) - { - Ok(_) => {} - - Err(error) => { println!("Error: {}", error); } - } - } - - pub fn set_ap_id(&mut self, id: ApId) - { - match id.into_bits(&mut self.data[0..2], &ApId::MASK_ARR) - { - Ok(_) => {} - - Err(error) => { println!("Error: {}", error); } - } - } -} - -impl FromBytes for PacketHeader -{ - type Error = &'static str; - - fn from_bytes(bytes: &[u8]) -> Result, Self::Error> - { - if bytes.len() < HEADER_SIZE { return Err("ERROR"); } - - let mut header = PacketHeader { data: [0u8; HEADER_SIZE] }; - - header.data.copy_from_slice(&bytes[0..HEADER_SIZE]); - - Ok(Parsed::new(HEADER_SIZE, header)) - } -} - -impl IntoBytes for PacketHeader -{ - type Error = &'static str; - - fn into_bytes(self, buffer: &mut [u8]) -> Result - { - if buffer.len() < HEADER_SIZE { return Err("ERROR"); } - - buffer[0..HEADER_SIZE].copy_from_slice(&self.data); - - Ok(HEADER_SIZE) - } -} - diff --git a/src/header/apid.rs b/src/header/apid.rs new file mode 100644 index 0000000..26ebf0c --- /dev/null +++ b/src/header/apid.rs @@ -0,0 +1,123 @@ +use crate::check_buffer_len; +use crate::bits::*; +use crate::error::PacketError; + + +/// # Application Process Identifier +/// +/// The APID shall provide the naming mechanism for the managed data path. +/// +/// The APID may uniquely identify the individual sending or receiving application +/// process within a particular space vehicle. +/// +/// For Idle Packets the APID shall be ‘11111111111’. +/// +/// ## NOTES +/// - The APID is unique only within its naming domain. +/// - There are no restrictions on the selection of APIDs except for the APID +/// for Idle Packets stated above. In particular, APIDs are not required to +/// be numbered consecutively. +/// - The Recommended Standard used a reserved APID to carry specific PDUs by, +/// for example, CFDP and LTP. This capability of acting as ‘shim’ protocol +/// is preserved; that is, SPP can still carry PDUs of other protocols, but +/// the coupling of APIDs to protocols is now mission specific. Missions may +/// use the optional Packet Secondary Header to create an extended naming +/// domain, but such uses are not specifically defined in this protocol. +/// This is reflected by the fact that the only reserved value is now the +/// one for Idle Packets. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ApId +{ + value: u16 +} + +impl ApId +{ + /// The 16 bit version of the mask for the ApId bits in the header. + pub const MASK_U16: u16 = 0b0000011111111111; + + /// The 8 bit array version of the mask for the ApId bits in the header. + /// The + pub const MASK_ARR: [u8; 2] = [0b00000111, 0b11111111]; +} + +impl From for ApId +{ + fn from(value: u16) -> Self + { + ApId + { + value + } + } +} + +impl From for u16 +{ + fn from(apid: ApId) -> u16 + { + apid.value + } +} + +impl FromBytes for ApId +{ + type Error = PacketError; + + fn from_bytes(bytes: &[u8]) -> Result, Self::Error> + { + check_buffer_len!(2usize, bytes); + + let id: u16 = (((bytes[0] & ApId::MASK_ARR[0]) as u16) << 8) | + (((bytes[1] & ApId::MASK_ARR[1]) as u16)); + + Ok(Parsed::new(2usize, id.into())) + } +} + +impl IntoBytes for ApId +{ + type Error = PacketError; + + fn into_bytes(self, buffer: &mut [u8]) -> Result + { + check_buffer_len!(2usize, buffer); + + let id: u16 = self.value; + + buffer[0] = ((id >> 8) as u8) & ApId::MASK_ARR[0]; + buffer[1] = (id as u8) & ApId::MASK_ARR[1]; + + Ok(2usize) + } +} + +impl FromBits for ApId +{ + type Error = PacketError; + + fn from_bits(bytes: &[u8], mask: &[u8]) -> Result + { + check_buffer_len!(2usize, bytes, mask); + + let id: u16 = (((bytes[0] & mask[0]) as u16) << 8) | + ((bytes[1] & mask[1]) as u16); + + Ok(id.into()) + } +} + +impl IntoBits for ApId +{ + type Error = PacketError; + + fn into_bits(self, bytes: &mut [u8], mask: &[u8]) -> Result<(), Self::Error> + { + check_buffer_len!(2usize, bytes, mask); + + update_masked_bits_arr(&mut [bytes[0], bytes[1]], &[mask[0], mask[1]], + &self.value.to_be_bytes()); + + Ok(()) + } +} diff --git a/src/header/mod.rs b/src/header/mod.rs new file mode 100644 index 0000000..5827703 --- /dev/null +++ b/src/header/mod.rs @@ -0,0 +1,11 @@ +mod apid; +mod version; +mod packet_type; +mod sequence; + + + +pub use self::apid::ApId; +pub use self::version::Version; +pub use self::packet_type::PacketType; +pub use self::sequence::SequenceFlags; diff --git a/src/header/packet_type.rs b/src/header/packet_type.rs new file mode 100644 index 0000000..bcc9400 --- /dev/null +++ b/src/header/packet_type.rs @@ -0,0 +1,94 @@ +use crate::check_buffer_len; +use crate::bits::*; +use crate::error::PacketError; + + + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(u8)] +pub enum PacketType +{ + Telemetry = 0b00000000, + Telecommand = 0b00010000 +} + + +impl PacketType +{ + pub const MASK_U8: u8 = 0b00010000; + pub const MASK_ARR: [u8; 1] = [PacketType::MASK_U8]; +} + +impl FromBytes for PacketType +{ + type Error = PacketError; + + fn from_bytes(bytes: &[u8]) -> Result, Self::Error> + { + check_buffer_len!(1usize, bytes); + + const TELEMETRY: u8 = PacketType::Telemetry as u8; + const TELECOMMAND: u8 = PacketType::Telecommand as u8; + + match bytes[0] & PacketType::MASK_U8 + { + TELEMETRY => { Ok(Parsed::new(1usize, PacketType::Telemetry)) } + TELECOMMAND => { Ok(Parsed::new(1usize, PacketType::Telecommand)) } + + _ => { Err(PacketError::InvalidPacketType(bytes[0])) } + } + } +} + +impl IntoBytes for PacketType +{ + type Error = PacketError; + + fn into_bytes(self, buffer: &mut [u8]) -> Result + { + check_buffer_len!(1usize, buffer); + + buffer[0] = self as u8; + + Ok(1) + } +} + +impl FromBits for PacketType +{ + type Error = PacketError; + + fn from_bits(bytes: &[u8], mask: &[u8]) -> Result + { + check_buffer_len!(1usize, bytes, mask); + + const TELEMETRY: u8 = PacketType::Telemetry as u8; + const TELECOMMAND: u8 = PacketType::Telecommand as u8; + + match bytes[0] & mask[0] + { + TELEMETRY => { Ok(PacketType::Telemetry) } + TELECOMMAND => { Ok(PacketType::Telecommand) } + + _ => { Err(PacketError::InvalidPacketType(bytes[0])) } + } + } +} + +impl IntoBits for PacketType +{ + type Error = PacketError; + + fn into_bits(self, bytes: &mut [u8], mask: &[u8]) -> Result<(), Self::Error> + { + check_buffer_len!(1usize, bytes, mask); + + match self + { + PacketType::Telemetry => { bytes[0] |= (PacketType::Telemetry as u8) & mask[0]; } + PacketType::Telecommand => { bytes[0] |= (PacketType::Telecommand as u8) & mask[0]; } + } + + Ok(()) + } +} diff --git a/src/header/sequence.rs b/src/header/sequence.rs new file mode 100644 index 0000000..50558ce --- /dev/null +++ b/src/header/sequence.rs @@ -0,0 +1,211 @@ +use crate::check_buffer_len; +use crate::bits::*; +use crate::error::PacketError; + + + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(u8)] +pub enum SequenceFlags +{ + Continuation = 0b00000000, + FirstSegment = 0b01000000, + LastSegment = 0b10000000, + Unsegmented = 0b11000000 +} + + +impl SequenceFlags +{ + pub const MASK_U8: u8 = 0b11000000; + pub const MASK_ARR: [u8; 1] = [SequenceFlags::MASK_U8]; +} + +impl FromBytes for SequenceFlags +{ + type Error = PacketError; + + fn from_bytes(bytes: &[u8]) -> Result, Self::Error> + { + check_buffer_len!(1usize, bytes); + + const CONTINUATION: u8 = SequenceFlags::Continuation as u8; + const FIRST_SEGMENT: u8 = SequenceFlags::FirstSegment as u8; + const LAST_SEGMENT: u8 = SequenceFlags::LastSegment as u8; + const UNSEGMENTED: u8 = SequenceFlags::Unsegmented as u8; + + match bytes[0] & SequenceFlags::MASK_U8 + { + CONTINUATION => { Ok(Parsed::new(1usize, SequenceFlags::Continuation)) } + FIRST_SEGMENT => { Ok(Parsed::new(1usize, SequenceFlags::FirstSegment)) } + LAST_SEGMENT => { Ok(Parsed::new(1usize, SequenceFlags::LastSegment)) } + UNSEGMENTED => { Ok(Parsed::new(1usize, SequenceFlags::Unsegmented)) } + + _ => { Err(PacketError::InvalidSequenceFlag(bytes[0])) } + } + } +} + +impl IntoBytes for SequenceFlags +{ + type Error = PacketError; + + fn into_bytes(self, buffer: &mut [u8]) -> Result + { + check_buffer_len!(1usize, buffer); + + buffer[0] = self as u8; + Ok(1) + } +} + +impl FromBits for SequenceFlags +{ + type Error = PacketError; + + fn from_bits(bytes: &[u8], mask: &[u8]) -> Result + { + check_buffer_len!(1usize, bytes, mask); + + const CONTINUATION: u8 = SequenceFlags::Continuation as u8; + const FIRST_SEGMENT: u8 = SequenceFlags::FirstSegment as u8; + const LAST_SEGMENT: u8 = SequenceFlags::LastSegment as u8; + const UNSEGMENTED: u8 = SequenceFlags::Unsegmented as u8; + + match bytes[0] & mask[0] + { + CONTINUATION => Ok(SequenceFlags::Continuation), + FIRST_SEGMENT => Ok(SequenceFlags::FirstSegment), + LAST_SEGMENT => Ok(SequenceFlags::LastSegment), + UNSEGMENTED => Ok(SequenceFlags::Unsegmented), + + _ => { Err(PacketError::InvalidSequenceFlag(bytes[0])) } + } + } +} + +impl IntoBits for SequenceFlags +{ + type Error = PacketError; + + fn into_bits(self, bytes: &mut [u8], mask: &[u8]) -> Result<(), Self::Error> + { + check_buffer_len!(1usize, bytes, mask); + + let value = self as u8; + + bytes[0] &= !mask[0]; // Clear the bits defined by the mask + bytes[0] |= value & mask[0]; // Set the new bits + + Ok(()) + } +} + + + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct SequenceCount +{ + value: u16 +} + +impl SequenceCount +{ + pub const MAX_VALUE: u16 = 16383; + + // Sequence Count spans Byte 2 (bits 0-5) and Byte 3 (bits 0-7) + pub const MASK_U16: u16 = 0b0011111111111111; + pub const MASK_ARR: [u8; 2] = [0b00111111, 0b11111111]; // Low 6 bits of byte 2, all of byte 3 +} + + +impl From for SequenceCount +{ + fn from(value: u16) -> Self + { + // Ensure value respects the 14-bit maximum + SequenceCount { value: value & SequenceCount::MASK_U16 } + } +} + +impl From for u16 +{ + fn from(count: SequenceCount) -> u16 + { + count.value + } +} + +impl FromBytes for SequenceCount +{ + type Error = PacketError; + + fn from_bytes(bytes: &[u8]) -> Result, Self::Error> + { + check_buffer_len!(2usize, bytes); + + let val: u16 = (((bytes[0] & SequenceCount::MASK_ARR[0]) as u16) << 8) | + (((bytes[1] & SequenceCount::MASK_ARR[1]) as u16)); + + Ok(Parsed::new(2usize, val.into())) + } +} + +impl IntoBytes for SequenceCount +{ + type Error = PacketError; + + fn into_bytes(self, buffer: &mut [u8]) -> Result + { + check_buffer_len!(2usize, buffer); + + let val: u16 = self.value; + + buffer[0] = ((val >> 8) as u8) & SequenceCount::MASK_ARR[0]; + buffer[1] = (val as u8) & SequenceCount::MASK_ARR[1]; + + Ok(1) + } +} + + +impl FromBits for SequenceCount +{ + type Error = PacketError; + + fn from_bits(bytes: &[u8], mask: &[u8]) -> Result + { + check_buffer_len!(2usize, bytes, mask); + + let val: u16 = (((bytes[0] & mask[0]) as u16) << 8) | + ((bytes[1] & mask[1]) as u16); + + Ok(val.into()) + } +} + +impl IntoBits for SequenceCount +{ + type Error = PacketError; + + fn into_bits(self, bytes: &mut [u8], mask: &[u8]) -> Result<(), Self::Error> + { + check_buffer_len!(2usize, bytes, mask); + + let count: u16 = self.value; + + // Extract high 6 bits (which are the lowest 6 bits of byte 0 in the slice) + let high_byte = ((count >> 8) as u8) & mask[0]; + // Extract low 8 bits (which are all of byte 1 in the slice) + let low_byte = (count as u8) & mask[1]; + + // Clear existing bits and set new ones for both bytes + bytes[0] &= !mask[0]; + bytes[0] |= high_byte; + + bytes[1] &= !mask[1]; + bytes[1] |= low_byte; + + Ok(()) + } +} diff --git a/src/header/version.rs b/src/header/version.rs new file mode 100644 index 0000000..7853a6f --- /dev/null +++ b/src/header/version.rs @@ -0,0 +1,86 @@ +use crate::check_buffer_len; +use crate::bits::*; +use crate::error::PacketError; + + + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(u8)] +pub enum Version +{ + One = 0b00000000 +} + +impl Version +{ + pub const MASK_U8: u8 = 0b11100000; + pub const MASK_ARR: [u8; 1] = [Version::MASK_U8]; +} + +impl FromBytes for Version +{ + type Error = PacketError; + + fn from_bytes(bytes: &[u8]) -> Result, Self::Error> + { + check_buffer_len!(1usize, bytes); + + const VERSION_ONE: u8 = Version::One as u8; + let version = bytes[0] & Version::MASK_U8; + + match version + { + VERSION_ONE => { Ok(Parsed::new(1usize, Version::One)) } + + _ => { Err(PacketError::InvalidVersion(version)) } + } + } +} + +impl IntoBytes for Version +{ + type Error = PacketError; + + fn into_bytes(self, buffer: &mut [u8]) -> Result + { + check_buffer_len!(1usize, buffer); + + buffer[0] = Version::One as u8; + + Ok(1) + } +} + +impl FromBits for Version +{ + type Error = PacketError; + + fn from_bits(bytes: &[u8], mask: &[u8]) -> Result + { + const VERSION_ONE: u8 = Version::One as u8; + + check_buffer_len!(1usize, bytes, mask); + + let version = bytes[0] & mask[0]; + match version + { + VERSION_ONE => { Ok(Version::One) } + + _ => { Err(PacketError::InvalidVersion(version)) } + } + } +} + +impl IntoBits for Version +{ + type Error = PacketError; + + fn into_bits(self, bytes: &mut [u8], mask: &[u8]) -> Result<(), Self::Error> + { + check_buffer_len!(1usize, bytes, mask); + + update_masked_bits(&mut bytes[0], mask[0], (self as u8).to_be()); + + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 1559965..558a662 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,8 @@ mod project; mod bits; mod header; +mod error; pub use crate::bits::*; pub use crate::header::*; +pub use crate::error::*; diff --git a/src/packet.rs b/src/packet.rs new file mode 100644 index 0000000..5e48db8 --- /dev/null +++ b/src/packet.rs @@ -0,0 +1,16 @@ +use crate::prime_header:PrimaryHeader; +use crate::prime_header:PrimaryHeader; + + + +/// # Space Packet +/// This is the main piece of the Space Packet Protocol. +pub struct Packet +{ + /// The Primary Header, 6 octets. + primary: PrimaryHeader, + + /// The Secondary Header, + secondary: Option, + user_data: [u8] +}