This commit is contained in:
parent
143b0869a4
commit
afd9395cee
@ -71,7 +71,7 @@ version = "0.7.0-beta.0"
|
||||
# path = "../../spacepackets"
|
||||
git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git"
|
||||
# rev = ""
|
||||
branch = "update-lv-tlv"
|
||||
branch = "pdu-additions"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -7,7 +7,7 @@ use std::{
|
||||
|
||||
use super::{
|
||||
user::{CfdpUser, MetadataReceivedParams},
|
||||
State, TransactionId, TransactionStep, CRC_32,
|
||||
PacketInfo, PacketTarget, State, TransactionId, TransactionStep, CRC_32,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use spacepackets::{
|
||||
@ -20,7 +20,7 @@ use spacepackets::{
|
||||
CommonPduConfig, FileDirectiveType, PduError, PduHeader,
|
||||
},
|
||||
tlv::{msg_to_user::MsgToUserTlv, EntityIdTlv, TlvType},
|
||||
ConditionCode, PduType,
|
||||
ConditionCode, PduType, TransmissionMode,
|
||||
},
|
||||
util::UnsignedByteField,
|
||||
};
|
||||
@ -142,28 +142,29 @@ impl DestinationHandler {
|
||||
match self.state {
|
||||
State::Idle => todo!(),
|
||||
State::BusyClass1Nacked => self.fsm_nacked(cfdp_user),
|
||||
State::BusyClass2Acked => todo!(),
|
||||
State::BusyClass2Acked => todo!("acknowledged mode not implemented yet"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_packet(_raw_packet: &[u8]) -> Result<(), DestError> {
|
||||
todo!();
|
||||
//Ok(())
|
||||
}
|
||||
pub fn insert_packet_with_known_type(
|
||||
&mut self,
|
||||
pdu_type: PduType,
|
||||
pdu_directive: Option<FileDirectiveType>,
|
||||
raw_packet: &[u8],
|
||||
) -> Result<(), DestError> {
|
||||
match pdu_type {
|
||||
pub fn insert_packet(&mut self, packet_info: &PacketInfo) -> Result<(), DestError> {
|
||||
if packet_info.target() != PacketTarget::DestEntity {
|
||||
// Unwrap is okay here, a PacketInfo for a file data PDU should always have the
|
||||
// destination as the target.
|
||||
return Err(DestError::CantProcessPacketType(
|
||||
packet_info.pdu_directive().unwrap(),
|
||||
));
|
||||
}
|
||||
match packet_info.pdu_type {
|
||||
PduType::FileDirective => {
|
||||
if pdu_directive.is_none() {
|
||||
if packet_info.pdu_directive.is_none() {
|
||||
return Err(DestError::DirectiveExpected);
|
||||
}
|
||||
self.handle_file_directive(pdu_directive.unwrap(), raw_packet)
|
||||
self.handle_file_directive(
|
||||
packet_info.pdu_directive.unwrap(),
|
||||
packet_info.raw_packet,
|
||||
)
|
||||
}
|
||||
PduType::FileData => self.handle_file_data(raw_packet),
|
||||
PduType::FileData => self.handle_file_data(packet_info.raw_packet),
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,6 +263,13 @@ impl DestinationHandler {
|
||||
self.transaction_params.file_properties.dest_file_name_len = dest_name.len_value();
|
||||
self.transaction_params.pdu_conf = *metadata_pdu.pdu_header().common_pdu_conf();
|
||||
self.transaction_params.msgs_to_user_size = 0;
|
||||
if metadata_pdu.pdu_header().common_pdu_conf().trans_mode
|
||||
== TransmissionMode::Unacknowledged
|
||||
{
|
||||
self.state = State::BusyClass1Nacked;
|
||||
} else {
|
||||
self.state = State::BusyClass2Acked;
|
||||
}
|
||||
if metadata_pdu.options().is_some() {
|
||||
for option_tlv in metadata_pdu.options_iter().unwrap() {
|
||||
if option_tlv.is_standard_tlv()
|
||||
@ -459,6 +467,9 @@ impl DestinationHandler {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[allow(unused_imports)]
|
||||
use std::println;
|
||||
|
||||
use spacepackets::{
|
||||
cfdp::{lv::Lv, ChecksumType},
|
||||
util::{UbfU16, UnsignedByteFieldU16},
|
||||
@ -556,12 +567,14 @@ mod tests {
|
||||
#[test]
|
||||
fn test_empty_file_transfer() {
|
||||
let mut buf: [u8; 512] = [0; 512];
|
||||
let test_user = TestCfdpUser::default();
|
||||
let mut test_user = TestCfdpUser::default();
|
||||
let mut dest_handler = DestinationHandler::new(LOCAL_ID);
|
||||
init_check(&dest_handler);
|
||||
|
||||
let seq_num = UbfU16::new(0);
|
||||
let pdu_conf = CommonPduConfig::new_with_byte_fields(REMOTE_ID, LOCAL_ID, seq_num).unwrap();
|
||||
let mut pdu_conf =
|
||||
CommonPduConfig::new_with_byte_fields(REMOTE_ID, LOCAL_ID, seq_num).unwrap();
|
||||
pdu_conf.trans_mode = TransmissionMode::Unacknowledged;
|
||||
let pdu_header = PduHeader::new_no_file_data(pdu_conf, 0);
|
||||
let metadata_params = MetadataGenericParams::new(false, ChecksumType::Crc32, 0);
|
||||
let metadata_pdu = MetadataPdu::new(
|
||||
@ -574,11 +587,13 @@ mod tests {
|
||||
let written_len = metadata_pdu
|
||||
.write_to_bytes(&mut buf)
|
||||
.expect("writing metadata PDU failed");
|
||||
// TODO: Create Metadata PDU and EOF PDU for empty file transfer.
|
||||
dest_handler.insert_packet(
|
||||
PduType::FileDirective,
|
||||
Some(FileDirectiveType::MetadataPdu),
|
||||
&buf[..written_len],
|
||||
);
|
||||
let packet_info =
|
||||
PacketInfo::new(&buf[..written_len]).expect("generating packet info failed");
|
||||
let insert_result = dest_handler.insert_packet(&packet_info);
|
||||
if let Err(e) = insert_result {
|
||||
panic!("insert result error: {e}");
|
||||
}
|
||||
let result = dest_handler.state_machine(&mut test_user);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,21 @@
|
||||
use crc::{Crc, CRC_32_CKSUM};
|
||||
use spacepackets::util::UnsignedByteField;
|
||||
use spacepackets::{
|
||||
cfdp::{
|
||||
pdu::{FileDirectiveType, PduError, PduHeader},
|
||||
PduType,
|
||||
},
|
||||
util::UnsignedByteField,
|
||||
};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub mod dest;
|
||||
pub mod user;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct TransactionId {
|
||||
source_id: UnsignedByteField,
|
||||
seq_num: UnsignedByteField,
|
||||
@ -26,6 +36,7 @@ impl TransactionId {
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum TransactionStep {
|
||||
Idle = 0,
|
||||
TransactionStart = 1,
|
||||
@ -36,6 +47,7 @@ pub enum TransactionStep {
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum State {
|
||||
Idle = 0,
|
||||
BusyClass1Nacked = 2,
|
||||
@ -44,6 +56,105 @@ pub enum State {
|
||||
|
||||
pub const CRC_32: Crc<u32> = Crc::<u32>::new(&CRC_32_CKSUM);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum PacketTarget {
|
||||
SourceEntity,
|
||||
DestEntity,
|
||||
}
|
||||
|
||||
/// This is a helper struct which contains base information about a particular PDU packet.
|
||||
/// This is also necessary information for CFDP packet routing. For example, some packet types
|
||||
/// like file data PDUs can only be used by CFDP source entities.
|
||||
pub struct PacketInfo<'raw_packet> {
|
||||
pdu_type: PduType,
|
||||
pdu_directive: Option<FileDirectiveType>,
|
||||
target: PacketTarget,
|
||||
raw_packet: &'raw_packet [u8],
|
||||
}
|
||||
|
||||
impl<'raw> PacketInfo<'raw> {
|
||||
pub fn new(raw_packet: &'raw [u8]) -> Result<Self, PduError> {
|
||||
let (pdu_header, header_len) = PduHeader::from_bytes(raw_packet)?;
|
||||
if pdu_header.pdu_type() == PduType::FileData {
|
||||
return Ok(Self {
|
||||
pdu_type: pdu_header.pdu_type(),
|
||||
pdu_directive: None,
|
||||
target: PacketTarget::DestEntity,
|
||||
raw_packet,
|
||||
});
|
||||
}
|
||||
if pdu_header.pdu_datafield_len() < 1 {
|
||||
return Err(PduError::FormatError);
|
||||
}
|
||||
// Route depending on PDU type and directive type if applicable. Retrieve directive type
|
||||
// from the raw stream for better performance (with sanity and directive code check).
|
||||
// The routing is based on section 4.5 of the CFDP standard which specifies the PDU forwarding
|
||||
// procedure.
|
||||
let directive = FileDirectiveType::try_from(raw_packet[header_len]).map_err(|_| {
|
||||
PduError::InvalidDirectiveType {
|
||||
found: raw_packet[header_len],
|
||||
expected: None,
|
||||
}
|
||||
})?;
|
||||
let packet_target = match directive {
|
||||
// Section c) of 4.5.3: These PDUs should always be targeted towards the file sender a.k.a.
|
||||
// the source handler
|
||||
FileDirectiveType::NakPdu
|
||||
| FileDirectiveType::FinishedPdu
|
||||
| FileDirectiveType::KeepAlivePdu => PacketTarget::SourceEntity,
|
||||
// Section b) of 4.5.3: These PDUs should always be targeted towards the file receiver a.k.a.
|
||||
// the destination handler
|
||||
FileDirectiveType::MetadataPdu
|
||||
| FileDirectiveType::EofPdu
|
||||
| FileDirectiveType::PromptPdu => PacketTarget::DestEntity,
|
||||
// Section a): Recipient depends of the type of PDU that is being acknowledged. We can simply
|
||||
// extract the PDU type from the raw stream. If it is an EOF PDU, this packet is passed to
|
||||
// the source handler, for a Finished PDU, it is passed to the destination handler.
|
||||
FileDirectiveType::AckPdu => {
|
||||
let acked_directive = FileDirectiveType::try_from(raw_packet[header_len + 1])
|
||||
.map_err(|_| PduError::InvalidDirectiveType {
|
||||
found: raw_packet[header_len],
|
||||
expected: None,
|
||||
})?;
|
||||
if acked_directive == FileDirectiveType::EofPdu {
|
||||
PacketTarget::SourceEntity
|
||||
} else if acked_directive == FileDirectiveType::FinishedPdu {
|
||||
PacketTarget::DestEntity
|
||||
} else {
|
||||
// TODO: Maybe a better error? This might be confusing..
|
||||
return Err(PduError::InvalidDirectiveType {
|
||||
found: raw_packet[header_len + 1],
|
||||
expected: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(Self {
|
||||
pdu_type: pdu_header.pdu_type(),
|
||||
pdu_directive: Some(directive),
|
||||
target: packet_target,
|
||||
raw_packet,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn pdu_type(&self) -> PduType {
|
||||
self.pdu_type
|
||||
}
|
||||
|
||||
pub fn pdu_directive(&self) -> Option<FileDirectiveType> {
|
||||
self.pdu_directive
|
||||
}
|
||||
|
||||
pub fn target(&self) -> PacketTarget {
|
||||
self.target
|
||||
}
|
||||
|
||||
pub fn raw_packet(&self) -> &[u8] {
|
||||
self.raw_packet
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
|
Loading…
Reference in New Issue
Block a user