use bytes::{Bytes, BytesMut};
use primary_header::*;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum CcsdsParserStatus {
ValidPacket,
NotEnoughBytesForHeader,
ExceedsMaxPacketLength,
BelowMinPacketLength,
NotEnoughBytesPacketLength,
InvalidCcsdsVersion,
SecondaryHeaderInvalid,
ApidNotAllowed,
SyncNotFound,
}
#[derive(Debug, PartialEq, Clone)]
pub struct CcsdsParserConfig {
pub allowed_apids: Option<Vec<u16>>,
pub max_packet_length: Option<u32>,
pub min_packet_length: Option<u32>,
pub secondary_header_required: bool,
pub sync_bytes: Vec<u8>,
pub keep_sync: bool,
pub num_header_bytes: u32,
pub keep_header: bool,
pub num_footer_bytes: u32,
pub keep_footer: bool,
pub little_endian_header: bool,
}
impl CcsdsParserConfig {
pub fn new() -> CcsdsParserConfig {
CcsdsParserConfig {
allowed_apids: None,
max_packet_length: None,
min_packet_length: None,
secondary_header_required: false,
sync_bytes: Vec::new(),
keep_sync: false,
num_header_bytes: 0,
keep_header: false,
num_footer_bytes: 0,
keep_footer: false,
little_endian_header: false,
}
}
}
pub struct CcsdsParser {
pub bytes: BytesMut,
pub config: CcsdsParserConfig,
pub skipped_bytes: usize,
reached_end: bool,
}
impl CcsdsParser {
pub fn new() -> Self {
CcsdsParser {
bytes: BytesMut::new(),
config: CcsdsParserConfig::new(),
skipped_bytes: 0,
reached_end: false,
}
}
pub fn with_config(config: CcsdsParserConfig) -> Self {
CcsdsParser {
bytes: BytesMut::new(),
config: config,
skipped_bytes: 0,
reached_end: false,
}
}
pub fn allow_apid(&mut self, apid: u16) {
match self.config.allowed_apids {
None => {
let mut apids = Vec::new();
apids.push(apid);
self.config.allowed_apids = Some(apids);
},
Some(ref mut apids) => {
apids.push(apid);
},
}
}
pub fn recv_bytes(&mut self, new_bytes: Bytes) {
self.bytes.extend(new_bytes);
}
pub fn recv_slice(&mut self, new_bytes: &[u8]) {
self.bytes.extend_from_slice(new_bytes);
}
pub fn current_header(&self) -> Option<PrimaryHeader> {
let min_length = CCSDS_MIN_LENGTH +
self.config.num_header_bytes +
self.config.num_footer_bytes +
self.config.sync_bytes.len() as u32;
if self.bytes.len() < min_length as usize {
None
} else {
let start_of_header = self.config.sync_bytes.len() + self.config.num_header_bytes as usize;
let end_of_header = start_of_header + CCSDS_PRI_HEADER_SIZE_BYTES as usize;
let mut header_bytes:[u8; 6] = [0; 6];
header_bytes.clone_from_slice(&self.bytes[start_of_header..end_of_header]);
if self.config.little_endian_header {
Some(PrimaryHeader::from_slice(&header_bytes).unwrap())
} else {
Some(PrimaryHeader::from_slice(&header_bytes).unwrap())
}
}
}
pub fn current_status(&self) -> CcsdsParserStatus {
let pri_header;
if let Some(header) = self.current_header() {
pri_header = header;
} else {
return CcsdsParserStatus::NotEnoughBytesForHeader;
}
if self.config.sync_bytes.len() > 0 {
if !self.config.sync_bytes.iter().zip(self.bytes.iter()).all(|(b0, b1)| *b0 == *b1) {
return CcsdsParserStatus::SyncNotFound;
}
}
if let Some(max_length) = self.config.max_packet_length {
if pri_header.packet_length() > max_length {
return CcsdsParserStatus::ExceedsMaxPacketLength;
}
}
if let Some(min_length) = self.config.min_packet_length {
if pri_header.packet_length() < min_length {
return CcsdsParserStatus::BelowMinPacketLength;
}
}
if self.bytes.len() < self.full_packet_length() {
return CcsdsParserStatus::NotEnoughBytesPacketLength;
}
if pri_header.control.version() as u8 != CCSDS_VERSION {
return CcsdsParserStatus::InvalidCcsdsVersion;
}
if self.config.secondary_header_required &&
pri_header.control.secondary_header_flag() == SecondaryHeaderFlag::NotPresent {
return CcsdsParserStatus::SecondaryHeaderInvalid;
}
if let Some(ref apid_list) = self.config.allowed_apids {
if !apid_list.contains(&pri_header.control.apid()) {
return CcsdsParserStatus::ApidNotAllowed;
}
}
CcsdsParserStatus::ValidPacket
}
pub fn reject(&mut self) {
self.bytes.advance(1);
self.skipped_bytes += 1;
}
pub fn pull_packet(&mut self) -> Option<BytesMut> {
let mut parser_status = self.current_status();
while parser_status != CcsdsParserStatus::ValidPacket {
if (parser_status == CcsdsParserStatus::NotEnoughBytesForHeader) ||
(parser_status == CcsdsParserStatus::NotEnoughBytesPacketLength) {
return None;
}
self.reject();
parser_status = self.current_status();
}
let mut packet_length = self.current_header().unwrap().packet_length();
if self.config.keep_sync {
packet_length += self.config.sync_bytes.len() as u32;
} else {
self.bytes.advance(self.config.sync_bytes.len());
}
if self.config.keep_header {
packet_length += self.config.num_header_bytes;
} else {
self.bytes.advance(self.config.num_header_bytes as usize);
}
if self.config.keep_footer {
packet_length += self.config.num_footer_bytes;
}
let packet = self.bytes.split_to(packet_length as usize);
if !self.config.keep_footer {
self.bytes.advance(self.config.num_footer_bytes as usize);
}
return Some(packet);
}
fn full_packet_length(&self) -> usize {
let mut packet_length = self.current_header().unwrap().packet_length();
packet_length += self.config.sync_bytes.len() as u32;
packet_length += self.config.num_header_bytes;
packet_length += self.config.num_footer_bytes;
return packet_length as usize;
}
pub fn next(&mut self) -> Option<BytesMut> {
match self.pull_packet() {
Some(bytes) => {
Some(bytes)
},
None => {
if !self.reached_end {
if self.current_status() != CcsdsParserStatus::NotEnoughBytesForHeader {
self.bytes.advance(1);
self.skipped_bytes += 1;
self.pull_packet()
} else {
self.reached_end = true;
None
}
} else {
None
}
},
}
}
}