CFDP extracted to library #201
@ -25,6 +25,7 @@ optional = true
|
||||
[dependencies.satrs-shared]
|
||||
version = ">=0.1.3, <0.2"
|
||||
features = ["serde"]
|
||||
path = "../satrs-shared"
|
||||
|
||||
[dependencies.satrs-mib-codegen]
|
||||
path = "codegen"
|
||||
|
@ -29,6 +29,7 @@ trybuild = { version = "1", features = ["diff"] }
|
||||
|
||||
[dev-dependencies.satrs-shared]
|
||||
version = ">=0.1.3, <0.2"
|
||||
path = "../../satrs-shared"
|
||||
|
||||
[dev-dependencies.satrs-mib]
|
||||
path = ".."
|
||||
|
@ -22,8 +22,10 @@ version = "0.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.spacepackets]
|
||||
version = ">0.9, <=0.11"
|
||||
version = ">0.9"
|
||||
default-features = false
|
||||
git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets"
|
||||
branch = "cfdp-tlv-owned-type"
|
||||
|
||||
[features]
|
||||
serde = ["dep:serde", "spacepackets/serde"]
|
||||
|
@ -21,14 +21,17 @@ crc = "3"
|
||||
|
||||
[dependencies.satrs-shared]
|
||||
version = ">=0.1.3, <0.2"
|
||||
path = "../satrs-shared"
|
||||
|
||||
[dependencies.num_enum]
|
||||
version = ">0.5, <=0.7"
|
||||
default-features = false
|
||||
|
||||
[dependencies.spacepackets]
|
||||
version = "0.11"
|
||||
version = "0.12"
|
||||
default-features = false
|
||||
git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets"
|
||||
branch = "cfdp-tlv-owned-type"
|
||||
|
||||
[dependencies.cobs]
|
||||
git = "https://github.com/robamu/cobs.rs.git"
|
||||
|
@ -20,7 +20,7 @@ use spacepackets::{
|
||||
metadata::{MetadataGenericParams, MetadataPduReader},
|
||||
CfdpPdu, CommonPduConfig, FileDirectiveType, PduError, PduHeader, WritablePduPacket,
|
||||
},
|
||||
tlv::{msg_to_user::MsgToUserTlv, EntityIdTlv, GenericTlv, TlvType},
|
||||
tlv::{msg_to_user::MsgToUserTlv, EntityIdTlv, GenericTlv, ReadableTlv, TlvType},
|
||||
ChecksumType, ConditionCode, FaultHandlerCode, PduType, TransmissionMode,
|
||||
},
|
||||
util::{UnsignedByteField, UnsignedEnum},
|
||||
@ -94,6 +94,7 @@ struct TransactionParams<CheckTimer: CountdownProvider> {
|
||||
file_properties: FileProperties,
|
||||
cksum_buf: [u8; 1024],
|
||||
msgs_to_user_size: usize,
|
||||
// TODO: Should we make this configurable?
|
||||
msgs_to_user_buf: [u8; 1024],
|
||||
remote_cfg: Option<RemoteEntityConfig>,
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ use crate::time::CountdownProvider;
|
||||
pub mod dest;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod filestore;
|
||||
pub mod request;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod source;
|
||||
pub mod user;
|
||||
@ -332,7 +333,7 @@ pub trait UserFaultHookProvider {
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
struct DummyFaultHook {}
|
||||
pub struct DummyFaultHook {}
|
||||
|
||||
impl UserFaultHookProvider for DummyFaultHook {
|
||||
fn notice_of_suspension_cb(
|
||||
|
308
satrs/src/cfdp/request.rs
Normal file
308
satrs/src/cfdp/request.rs
Normal file
@ -0,0 +1,308 @@
|
||||
use spacepackets::{
|
||||
cfdp::{
|
||||
tlv::{GenericTlv, Tlv, TlvType},
|
||||
SegmentationControl, TransmissionMode,
|
||||
},
|
||||
util::UnsignedByteField,
|
||||
};
|
||||
|
||||
trait ReadablePutRequest {
|
||||
fn destination_id(&self) -> UnsignedByteField;
|
||||
fn source_file(&self) -> Option<&str>;
|
||||
fn dest_file(&self) -> Option<&str>;
|
||||
fn trans_mode(&self) -> Option<TransmissionMode>;
|
||||
fn closure_requested(&self) -> Option<bool>;
|
||||
fn seg_ctrl(&self) -> Option<SegmentationControl>;
|
||||
fn msgs_to_user(&self, f: impl FnMut(&Tlv));
|
||||
fn fault_handler_overrides(&self, f: impl FnMut(&Tlv));
|
||||
fn flow_label(&self) -> Option<Tlv>;
|
||||
fn fs_requests(&self, f: impl FnMut(&Tlv));
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct PutRequest<'src_file, 'dest_file, 'msgs_to_user, 'fh_ovrds, 'flow_label, 'fs_requests> {
|
||||
pub destination_id: UnsignedByteField,
|
||||
pub source_file: Option<&'src_file str>,
|
||||
pub dest_file: Option<&'dest_file str>,
|
||||
pub trans_mode: Option<TransmissionMode>,
|
||||
pub closure_requested: Option<bool>,
|
||||
pub seg_ctrl: Option<SegmentationControl>,
|
||||
pub msgs_to_user: Option<&'msgs_to_user [Tlv<'msgs_to_user>]>,
|
||||
pub fault_handler_overrides: Option<&'fh_ovrds [Tlv<'fh_ovrds>]>,
|
||||
pub flow_label: Option<Tlv<'flow_label>>,
|
||||
pub fs_requests: Option<&'fs_requests [Tlv<'fs_requests>]>,
|
||||
}
|
||||
|
||||
impl ReadablePutRequest for PutRequest<'_, '_, '_, '_, '_, '_> {
|
||||
fn destination_id(&self) -> UnsignedByteField {
|
||||
self.destination_id
|
||||
}
|
||||
|
||||
fn source_file(&self) -> Option<&str> {
|
||||
self.source_file
|
||||
}
|
||||
|
||||
fn dest_file(&self) -> Option<&str> {
|
||||
self.dest_file
|
||||
}
|
||||
|
||||
fn trans_mode(&self) -> Option<TransmissionMode> {
|
||||
self.trans_mode
|
||||
}
|
||||
|
||||
fn closure_requested(&self) -> Option<bool> {
|
||||
self.closure_requested
|
||||
}
|
||||
|
||||
fn seg_ctrl(&self) -> Option<SegmentationControl> {
|
||||
self.seg_ctrl
|
||||
}
|
||||
|
||||
fn msgs_to_user(&self, mut f: impl FnMut(&Tlv)) {
|
||||
if let Some(msgs_to_user) = self.msgs_to_user {
|
||||
for msg_to_user in msgs_to_user {
|
||||
f(msg_to_user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fault_handler_overrides(&self, mut f: impl FnMut(&Tlv)) {
|
||||
if let Some(fh_overrides) = self.fault_handler_overrides {
|
||||
for fh_override in fh_overrides {
|
||||
f(fh_override)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flow_label(&self) -> Option<Tlv> {
|
||||
self.flow_label
|
||||
}
|
||||
|
||||
fn fs_requests(&self, mut f: impl FnMut(&Tlv)) {
|
||||
if let Some(fs_requests) = self.fs_requests {
|
||||
for fs_request in fs_requests {
|
||||
f(fs_request)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src_file, 'dest_file> PutRequest<'src_file, 'dest_file, 'static, 'static, 'static, 'static> {
|
||||
pub fn new_regular_request(
|
||||
dest_id: UnsignedByteField,
|
||||
source_file: &'src_file str,
|
||||
dest_file: &'dest_file str,
|
||||
trans_mode: Option<TransmissionMode>,
|
||||
closure_requested: Option<bool>,
|
||||
) -> Self {
|
||||
Self {
|
||||
destination_id: dest_id,
|
||||
source_file: Some(source_file),
|
||||
dest_file: Some(dest_file),
|
||||
trans_mode,
|
||||
closure_requested,
|
||||
seg_ctrl: None,
|
||||
msgs_to_user: None,
|
||||
fault_handler_overrides: None,
|
||||
flow_label: None,
|
||||
fs_requests: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct TlvWithInvalidType(pub(crate) ());
|
||||
|
||||
impl<'msgs_to_user> PutRequest<'static, 'static, 'msgs_to_user, 'static, 'static, 'static> {
|
||||
pub fn new_msgs_to_user_only(
|
||||
dest_id: UnsignedByteField,
|
||||
msgs_to_user: &'msgs_to_user [Tlv<'msgs_to_user>],
|
||||
) -> Result<Self, TlvWithInvalidType> {
|
||||
Ok(Self {
|
||||
destination_id: dest_id,
|
||||
source_file: None,
|
||||
dest_file: None,
|
||||
trans_mode: None,
|
||||
closure_requested: None,
|
||||
seg_ctrl: None,
|
||||
msgs_to_user: Some(msgs_to_user),
|
||||
fault_handler_overrides: None,
|
||||
flow_label: None,
|
||||
fs_requests: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Uses [generic_tlv_list_type_check] to check the TLV type validity of all TLV fields.
|
||||
pub fn check_tlv_type_validities(&self) -> bool {
|
||||
generic_tlv_list_type_check(self.msgs_to_user, TlvType::MsgToUser);
|
||||
if let Some(msgs_to_user) = self.msgs_to_user {
|
||||
for msg_to_user in msgs_to_user {
|
||||
if msg_to_user.tlv_type().is_none() {
|
||||
return false;
|
||||
}
|
||||
if msg_to_user.tlv_type().unwrap() != TlvType::MsgToUser {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
generic_tlv_list_type_check(self.fault_handler_overrides, TlvType::FaultHandler);
|
||||
generic_tlv_list_type_check(self.fs_requests, TlvType::FilestoreRequest);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generic_tlv_list_type_check(opt_tlvs: Option<&[Tlv<'_>]>, tlv_type: TlvType) -> bool {
|
||||
if let Some(tlvs) = opt_tlvs {
|
||||
for tlv in tlvs {
|
||||
if tlv.tlv_type().is_none() {
|
||||
return false;
|
||||
}
|
||||
if tlv.tlv_type().unwrap() != tlv_type {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod alloc_mod {
|
||||
use super::*;
|
||||
use alloc::string::ToString;
|
||||
use spacepackets::cfdp::tlv::{msg_to_user::MsgToUserTlv, TlvOwned};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct PutRequestOwned {
|
||||
pub destination_id: UnsignedByteField,
|
||||
pub source_file: Option<alloc::string::String>,
|
||||
pub dest_file: Option<alloc::string::String>,
|
||||
pub trans_mode: Option<TransmissionMode>,
|
||||
pub closure_requested: Option<bool>,
|
||||
pub seg_ctrl: Option<SegmentationControl>,
|
||||
pub msgs_to_user: Option<alloc::vec::Vec<TlvOwned>>,
|
||||
pub fault_handler_overrides: Option<alloc::vec::Vec<TlvOwned>>,
|
||||
pub flow_label: Option<TlvOwned>,
|
||||
pub fs_requests: Option<alloc::vec::Vec<TlvOwned>>,
|
||||
}
|
||||
|
||||
impl PutRequestOwned {
|
||||
pub fn new_regular_request(
|
||||
dest_id: UnsignedByteField,
|
||||
source_file: &str,
|
||||
dest_file: &str,
|
||||
trans_mode: Option<TransmissionMode>,
|
||||
closure_requested: Option<bool>,
|
||||
) -> Self {
|
||||
Self {
|
||||
destination_id: dest_id,
|
||||
source_file: Some(source_file.to_string()),
|
||||
dest_file: Some(dest_file.to_string()),
|
||||
trans_mode,
|
||||
closure_requested,
|
||||
seg_ctrl: None,
|
||||
msgs_to_user: None,
|
||||
fault_handler_overrides: None,
|
||||
flow_label: None,
|
||||
fs_requests: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_msgs_to_user_only(
|
||||
dest_id: UnsignedByteField,
|
||||
msgs_to_user: &[MsgToUserTlv<'_>],
|
||||
) -> Result<Self, TlvWithInvalidType> {
|
||||
Ok(Self {
|
||||
destination_id: dest_id,
|
||||
source_file: None,
|
||||
dest_file: None,
|
||||
trans_mode: None,
|
||||
closure_requested: None,
|
||||
seg_ctrl: None,
|
||||
msgs_to_user: Some(msgs_to_user.iter().map(|msg| msg.tlv.to_owned()).collect()),
|
||||
fault_handler_overrides: None,
|
||||
flow_label: None,
|
||||
fs_requests: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PutRequest<'_, '_, '_, '_, '_, '_>> for PutRequestOwned {
|
||||
fn from(req: PutRequest<'_, '_, '_, '_, '_, '_>) -> Self {
|
||||
Self {
|
||||
destination_id: req.destination_id,
|
||||
source_file: req.source_file.map(|s| s.into()),
|
||||
dest_file: req.dest_file.map(|s| s.into()),
|
||||
trans_mode: req.trans_mode,
|
||||
closure_requested: req.closure_requested,
|
||||
seg_ctrl: req.seg_ctrl,
|
||||
msgs_to_user: req
|
||||
.msgs_to_user
|
||||
.map(|msgs_to_user| msgs_to_user.iter().map(|msg| msg.to_owned()).collect()),
|
||||
fault_handler_overrides: req
|
||||
.msgs_to_user
|
||||
.map(|fh_overides| fh_overides.iter().map(|msg| msg.to_owned()).collect()),
|
||||
flow_label: req
|
||||
.flow_label
|
||||
.map(|flow_label_tlv| flow_label_tlv.to_owned()),
|
||||
fs_requests: req
|
||||
.fs_requests
|
||||
.map(|fs_requests| fs_requests.iter().map(|msg| msg.to_owned()).collect()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadablePutRequest for PutRequestOwned {
|
||||
fn destination_id(&self) -> UnsignedByteField {
|
||||
self.destination_id
|
||||
}
|
||||
|
||||
fn source_file(&self) -> Option<&str> {
|
||||
self.source_file.as_deref()
|
||||
}
|
||||
|
||||
fn dest_file(&self) -> Option<&str> {
|
||||
self.dest_file.as_deref()
|
||||
}
|
||||
|
||||
fn trans_mode(&self) -> Option<TransmissionMode> {
|
||||
self.trans_mode
|
||||
}
|
||||
|
||||
fn closure_requested(&self) -> Option<bool> {
|
||||
self.closure_requested
|
||||
}
|
||||
|
||||
fn seg_ctrl(&self) -> Option<SegmentationControl> {
|
||||
self.seg_ctrl
|
||||
}
|
||||
|
||||
fn msgs_to_user(&self, mut f: impl FnMut(&Tlv)) {
|
||||
if let Some(msgs_to_user) = &self.msgs_to_user {
|
||||
for msg_to_user in msgs_to_user {
|
||||
f(&msg_to_user.as_tlv())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fault_handler_overrides(&self, mut f: impl FnMut(&Tlv)) {
|
||||
if let Some(fh_overrides) = &self.fault_handler_overrides {
|
||||
for fh_override in fh_overrides {
|
||||
f(&fh_override.as_tlv())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flow_label(&self) -> Option<Tlv> {
|
||||
self.flow_label.as_ref().map(|tlv| tlv.as_tlv())
|
||||
}
|
||||
|
||||
fn fs_requests(&self, mut f: impl FnMut(&Tlv)) {
|
||||
if let Some(fs_requests) = &self.fs_requests {
|
||||
for fs_request in fs_requests {
|
||||
f(&fs_request.as_tlv())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user