CFDP extracted to library #201
@ -25,6 +25,7 @@ optional = true
|
|||||||
[dependencies.satrs-shared]
|
[dependencies.satrs-shared]
|
||||||
version = ">=0.1.3, <0.2"
|
version = ">=0.1.3, <0.2"
|
||||||
features = ["serde"]
|
features = ["serde"]
|
||||||
|
path = "../satrs-shared"
|
||||||
|
|
||||||
[dependencies.satrs-mib-codegen]
|
[dependencies.satrs-mib-codegen]
|
||||||
path = "codegen"
|
path = "codegen"
|
||||||
|
@ -29,6 +29,7 @@ trybuild = { version = "1", features = ["diff"] }
|
|||||||
|
|
||||||
[dev-dependencies.satrs-shared]
|
[dev-dependencies.satrs-shared]
|
||||||
version = ">=0.1.3, <0.2"
|
version = ">=0.1.3, <0.2"
|
||||||
|
path = "../../satrs-shared"
|
||||||
|
|
||||||
[dev-dependencies.satrs-mib]
|
[dev-dependencies.satrs-mib]
|
||||||
path = ".."
|
path = ".."
|
||||||
|
@ -22,8 +22,10 @@ version = "0.3"
|
|||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dependencies.spacepackets]
|
[dependencies.spacepackets]
|
||||||
version = ">0.9, <=0.11"
|
version = ">0.9"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets"
|
||||||
|
branch = "cfdp-tlv-owned-type"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
serde = ["dep:serde", "spacepackets/serde"]
|
serde = ["dep:serde", "spacepackets/serde"]
|
||||||
|
@ -21,14 +21,17 @@ crc = "3"
|
|||||||
|
|
||||||
[dependencies.satrs-shared]
|
[dependencies.satrs-shared]
|
||||||
version = ">=0.1.3, <0.2"
|
version = ">=0.1.3, <0.2"
|
||||||
|
path = "../satrs-shared"
|
||||||
|
|
||||||
[dependencies.num_enum]
|
[dependencies.num_enum]
|
||||||
version = ">0.5, <=0.7"
|
version = ">0.5, <=0.7"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[dependencies.spacepackets]
|
[dependencies.spacepackets]
|
||||||
version = "0.11"
|
version = "0.12"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets"
|
||||||
|
branch = "cfdp-tlv-owned-type"
|
||||||
|
|
||||||
[dependencies.cobs]
|
[dependencies.cobs]
|
||||||
git = "https://github.com/robamu/cobs.rs.git"
|
git = "https://github.com/robamu/cobs.rs.git"
|
||||||
|
@ -20,7 +20,7 @@ use spacepackets::{
|
|||||||
metadata::{MetadataGenericParams, MetadataPduReader},
|
metadata::{MetadataGenericParams, MetadataPduReader},
|
||||||
CfdpPdu, CommonPduConfig, FileDirectiveType, PduError, PduHeader, WritablePduPacket,
|
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,
|
ChecksumType, ConditionCode, FaultHandlerCode, PduType, TransmissionMode,
|
||||||
},
|
},
|
||||||
util::{UnsignedByteField, UnsignedEnum},
|
util::{UnsignedByteField, UnsignedEnum},
|
||||||
@ -94,6 +94,7 @@ struct TransactionParams<CheckTimer: CountdownProvider> {
|
|||||||
file_properties: FileProperties,
|
file_properties: FileProperties,
|
||||||
cksum_buf: [u8; 1024],
|
cksum_buf: [u8; 1024],
|
||||||
msgs_to_user_size: usize,
|
msgs_to_user_size: usize,
|
||||||
|
// TODO: Should we make this configurable?
|
||||||
msgs_to_user_buf: [u8; 1024],
|
msgs_to_user_buf: [u8; 1024],
|
||||||
remote_cfg: Option<RemoteEntityConfig>,
|
remote_cfg: Option<RemoteEntityConfig>,
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ use crate::time::CountdownProvider;
|
|||||||
pub mod dest;
|
pub mod dest;
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub mod filestore;
|
pub mod filestore;
|
||||||
|
pub mod request;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub mod source;
|
pub mod source;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
@ -332,7 +333,7 @@ pub trait UserFaultHookProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
struct DummyFaultHook {}
|
pub struct DummyFaultHook {}
|
||||||
|
|
||||||
impl UserFaultHookProvider for DummyFaultHook {
|
impl UserFaultHookProvider for DummyFaultHook {
|
||||||
fn notice_of_suspension_cb(
|
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