163 lines
5.3 KiB
Rust
Raw Normal View History

2023-08-05 18:51:50 +02:00
use crc::{Crc, CRC_32_CKSUM};
2023-08-17 22:11:27 +02:00
use spacepackets::{
cfdp::{
pdu::{FileDirectiveType, PduError, PduHeader},
PduType,
},
util::UnsignedByteField,
};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
2023-08-05 18:51:50 +02:00
2023-08-16 19:51:26 +02:00
#[cfg(feature = "std")]
2023-07-21 20:23:24 +02:00
pub mod dest;
2023-08-11 12:44:24 +02:00
pub mod user;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
2023-08-17 22:11:27 +02:00
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2023-08-11 12:44:24 +02:00
pub struct TransactionId {
source_id: UnsignedByteField,
seq_num: UnsignedByteField,
}
impl TransactionId {
pub fn new(source_id: UnsignedByteField, seq_num: UnsignedByteField) -> Self {
Self { source_id, seq_num }
}
pub fn source_id(&self) -> &UnsignedByteField {
&self.source_id
}
pub fn seq_num(&self) -> &UnsignedByteField {
&self.seq_num
}
}
2023-07-21 20:23:24 +02:00
2023-07-26 22:27:02 +02:00
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2023-08-17 22:11:27 +02:00
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2023-07-21 20:23:24 +02:00
pub enum TransactionStep {
Idle = 0,
TransactionStart = 1,
ReceivingFileDataPdus = 2,
SendingAckPdu = 3,
TransferCompletion = 4,
2023-07-21 21:36:21 +02:00
SendingFinishedPdu = 5,
2023-07-21 20:23:24 +02:00
}
2023-07-26 22:27:02 +02:00
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2023-08-17 22:11:27 +02:00
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2023-07-21 20:23:24 +02:00
pub enum State {
Idle = 0,
BusyClass1Nacked = 2,
BusyClass2Acked = 3,
}
2023-08-05 18:51:50 +02:00
pub const CRC_32: Crc<u32> = Crc::<u32>::new(&CRC_32_CKSUM);
2023-08-17 22:11:27 +02:00
#[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
}
}
2023-07-21 20:23:24 +02:00
#[cfg(test)]
mod tests {
#[test]
2023-07-21 21:36:21 +02:00
fn basic_test() {}
2023-07-21 20:23:24 +02:00
}