Header stuctures and enum complete.
The header was split into individual files to make it easier to manage. enums that were just a u8 or u16 with determinate values now are set in the definition instead of using const values. Errors were added. Some of these are just best guesses at what is needed at this time. Added a macro to the bits for checking buffer and mask length. This keeps the error generation consistent and makes the code easy to read. Started, but have not finished the packet stuff. I want it to have a view and a builder.
This commit is contained in:
81
src/bits.rs
81
src/bits.rs
@ -15,7 +15,7 @@ pub trait FromBytes: Sized
|
|||||||
/// A [`Parsed`] struct with the parsed value and bytes consumed, or an error.
|
/// A [`Parsed`] struct with the parsed value and bytes consumed, or an error.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```text
|
||||||
/// ```
|
/// ```
|
||||||
fn from_bytes(bytes: &[u8]) -> Result<Parsed<Self>, Self::Error>;
|
fn from_bytes(bytes: &[u8]) -> Result<Parsed<Self>, Self::Error>;
|
||||||
}
|
}
|
||||||
@ -108,3 +108,82 @@ impl<T> Parsed<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
69
src/error.rs
Normal file
69
src/error.rs
Normal file
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
392
src/header.rs
392
src/header.rs
@ -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<u16> for ApId
|
|
||||||
{
|
|
||||||
fn from(value: u16) -> Self
|
|
||||||
{
|
|
||||||
ApId
|
|
||||||
{
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ApId> for u16
|
|
||||||
{
|
|
||||||
fn from(apid: ApId) -> u16
|
|
||||||
{
|
|
||||||
apid.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromBytes for ApId
|
|
||||||
{
|
|
||||||
type Error = &'static str;
|
|
||||||
|
|
||||||
fn from_bytes(bytes: &[u8]) -> Result<Parsed<Self>, 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<usize, Self::Error>
|
|
||||||
{
|
|
||||||
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<Self, Self::Error>
|
|
||||||
{
|
|
||||||
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<Parsed<Self>, 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<usize, Self::Error>
|
|
||||||
{
|
|
||||||
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<Self, Self::Error>
|
|
||||||
{
|
|
||||||
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<Parsed<Self>, 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<usize, Self::Error>
|
|
||||||
{
|
|
||||||
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<Self, Self::Error>
|
|
||||||
{
|
|
||||||
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<Parsed<Self>, 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<usize, Self::Error>
|
|
||||||
{
|
|
||||||
if buffer.len() < HEADER_SIZE { return Err("ERROR"); }
|
|
||||||
|
|
||||||
buffer[0..HEADER_SIZE].copy_from_slice(&self.data);
|
|
||||||
|
|
||||||
Ok(HEADER_SIZE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
123
src/header/apid.rs
Normal file
123
src/header/apid.rs
Normal file
@ -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<u16> for ApId
|
||||||
|
{
|
||||||
|
fn from(value: u16) -> Self
|
||||||
|
{
|
||||||
|
ApId
|
||||||
|
{
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ApId> for u16
|
||||||
|
{
|
||||||
|
fn from(apid: ApId) -> u16
|
||||||
|
{
|
||||||
|
apid.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromBytes for ApId
|
||||||
|
{
|
||||||
|
type Error = PacketError;
|
||||||
|
|
||||||
|
fn from_bytes(bytes: &[u8]) -> Result<Parsed<Self>, 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<usize, Self::Error>
|
||||||
|
{
|
||||||
|
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<Self, Self::Error>
|
||||||
|
{
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/header/mod.rs
Normal file
11
src/header/mod.rs
Normal file
@ -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;
|
||||||
94
src/header/packet_type.rs
Normal file
94
src/header/packet_type.rs
Normal file
@ -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<Parsed<Self>, 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<usize, Self::Error>
|
||||||
|
{
|
||||||
|
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<Self, Self::Error>
|
||||||
|
{
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
211
src/header/sequence.rs
Normal file
211
src/header/sequence.rs
Normal file
@ -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<Parsed<Self>, 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<usize, Self::Error>
|
||||||
|
{
|
||||||
|
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<Self, Self::Error>
|
||||||
|
{
|
||||||
|
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<u16> for SequenceCount
|
||||||
|
{
|
||||||
|
fn from(value: u16) -> Self
|
||||||
|
{
|
||||||
|
// Ensure value respects the 14-bit maximum
|
||||||
|
SequenceCount { value: value & SequenceCount::MASK_U16 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SequenceCount> for u16
|
||||||
|
{
|
||||||
|
fn from(count: SequenceCount) -> u16
|
||||||
|
{
|
||||||
|
count.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromBytes for SequenceCount
|
||||||
|
{
|
||||||
|
type Error = PacketError;
|
||||||
|
|
||||||
|
fn from_bytes(bytes: &[u8]) -> Result<Parsed<Self>, 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<usize, Self::Error>
|
||||||
|
{
|
||||||
|
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<Self, Self::Error>
|
||||||
|
{
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
86
src/header/version.rs
Normal file
86
src/header/version.rs
Normal file
@ -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<Parsed<Self>, 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<usize, Self::Error>
|
||||||
|
{
|
||||||
|
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<Self, Self::Error>
|
||||||
|
{
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,6 +17,8 @@ mod project;
|
|||||||
|
|
||||||
mod bits;
|
mod bits;
|
||||||
mod header;
|
mod header;
|
||||||
|
mod error;
|
||||||
|
|
||||||
pub use crate::bits::*;
|
pub use crate::bits::*;
|
||||||
pub use crate::header::*;
|
pub use crate::header::*;
|
||||||
|
pub use crate::error::*;
|
||||||
|
|||||||
16
src/packet.rs
Normal file
16
src/packet.rs
Normal file
@ -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<SecondaryHeader>,
|
||||||
|
user_data: [u8]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user