come on, neotest..
Some checks failed
Rust/sat-rs/pipeline/pr-main There was a failure building this commit
Some checks failed
Rust/sat-rs/pipeline/pr-main There was a failure building this commit
This commit is contained in:
parent
51d3c9b6e8
commit
c766ab2d71
@ -8,9 +8,10 @@ use std::{
|
|||||||
use crate::cfdp::user::TransactionFinishedParams;
|
use crate::cfdp::user::TransactionFinishedParams;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
filestore::{NativeFilestore, VirtualFilestore},
|
||||||
user::{CfdpUser, MetadataReceivedParams},
|
user::{CfdpUser, MetadataReceivedParams},
|
||||||
CheckTimerCreator, PacketInfo, PacketTarget, RemoteEntityConfigProvider, State, TransactionId,
|
CheckTimerCreator, DefaultFaultHandler, PacketInfo, PacketTarget, RemoteEntityConfig,
|
||||||
TransactionStep, CRC_32,
|
RemoteEntityConfigProvider, State, TransactionId, TransactionStep, CRC_32,
|
||||||
};
|
};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
@ -21,10 +22,10 @@ use spacepackets::{
|
|||||||
file_data::FileDataPdu,
|
file_data::FileDataPdu,
|
||||||
finished::{DeliveryCode, FileStatus, FinishedPduCreator},
|
finished::{DeliveryCode, FileStatus, FinishedPduCreator},
|
||||||
metadata::{MetadataGenericParams, MetadataPduReader},
|
metadata::{MetadataGenericParams, MetadataPduReader},
|
||||||
CommonPduConfig, FileDirectiveType, PduError, PduHeader, WritablePduPacket, CfdpPdu,
|
CfdpPdu, CommonPduConfig, FileDirectiveType, PduError, PduHeader, WritablePduPacket,
|
||||||
},
|
},
|
||||||
tlv::{msg_to_user::MsgToUserTlv, EntityIdTlv, TlvType, GenericTlv},
|
tlv::{msg_to_user::MsgToUserTlv, EntityIdTlv, GenericTlv, TlvType},
|
||||||
ConditionCode, PduType,
|
ConditionCode, FaultHandlerCode, PduType, TransmissionMode,
|
||||||
},
|
},
|
||||||
util::UnsignedByteField,
|
util::UnsignedByteField,
|
||||||
};
|
};
|
||||||
@ -36,6 +37,8 @@ pub struct DestinationHandler {
|
|||||||
state: State,
|
state: State,
|
||||||
tparams: TransactionParams,
|
tparams: TransactionParams,
|
||||||
packets_to_send_ctx: PacketsToSendContext,
|
packets_to_send_ctx: PacketsToSendContext,
|
||||||
|
vfs: Box<dyn VirtualFilestore>,
|
||||||
|
default_fault_handler: DefaultFaultHandler,
|
||||||
remote_cfg_table: Box<dyn RemoteEntityConfigProvider>,
|
remote_cfg_table: Box<dyn RemoteEntityConfigProvider>,
|
||||||
check_timer_creator: Box<dyn CheckTimerCreator>,
|
check_timer_creator: Box<dyn CheckTimerCreator>,
|
||||||
}
|
}
|
||||||
@ -77,6 +80,7 @@ impl Default for TransferState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct TransactionParams {
|
struct TransactionParams {
|
||||||
tstate: TransferState,
|
tstate: TransferState,
|
||||||
@ -85,6 +89,13 @@ struct TransactionParams {
|
|||||||
cksum_buf: [u8; 1024],
|
cksum_buf: [u8; 1024],
|
||||||
msgs_to_user_size: usize,
|
msgs_to_user_size: usize,
|
||||||
msgs_to_user_buf: [u8; 1024],
|
msgs_to_user_buf: [u8; 1024],
|
||||||
|
remote_cfg: Option<RemoteEntityConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TransactionParams {
|
||||||
|
fn transmission_mode(&self) -> TransmissionMode {
|
||||||
|
self.pdu_conf.trans_mode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FileProperties {
|
impl Default for FileProperties {
|
||||||
@ -118,6 +129,7 @@ impl Default for TransactionParams {
|
|||||||
msgs_to_user_buf: [0; 1024],
|
msgs_to_user_buf: [0; 1024],
|
||||||
tstate: Default::default(),
|
tstate: Default::default(),
|
||||||
file_properties: Default::default(),
|
file_properties: Default::default(),
|
||||||
|
remote_cfg: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,11 +165,15 @@ pub enum DestError {
|
|||||||
PathConversion(#[from] Utf8Error),
|
PathConversion(#[from] Utf8Error),
|
||||||
#[error("error building dest path from source file name and dest folder")]
|
#[error("error building dest path from source file name and dest folder")]
|
||||||
PathConcatError,
|
PathConcatError,
|
||||||
|
#[error("no remote entity configuration found for {0:?}")]
|
||||||
|
NoRemoteCfgFound(UnsignedByteField),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DestinationHandler {
|
impl DestinationHandler {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
entity_id: impl Into<UnsignedByteField>,
|
entity_id: impl Into<UnsignedByteField>,
|
||||||
|
vfs: Box<dyn VirtualFilestore>,
|
||||||
|
default_fault_handler: DefaultFaultHandler,
|
||||||
remote_cfg_table: Box<dyn RemoteEntityConfigProvider>,
|
remote_cfg_table: Box<dyn RemoteEntityConfigProvider>,
|
||||||
check_timer_creator: Box<dyn CheckTimerCreator>,
|
check_timer_creator: Box<dyn CheckTimerCreator>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -167,6 +183,8 @@ impl DestinationHandler {
|
|||||||
state: State::Idle,
|
state: State::Idle,
|
||||||
tparams: Default::default(),
|
tparams: Default::default(),
|
||||||
packets_to_send_ctx: Default::default(),
|
packets_to_send_ctx: Default::default(),
|
||||||
|
vfs,
|
||||||
|
default_fault_handler,
|
||||||
remote_cfg_table,
|
remote_cfg_table,
|
||||||
check_timer_creator,
|
check_timer_creator,
|
||||||
}
|
}
|
||||||
@ -286,6 +304,15 @@ impl DestinationHandler {
|
|||||||
let metadata_pdu = MetadataPduReader::from_bytes(raw_packet)?;
|
let metadata_pdu = MetadataPduReader::from_bytes(raw_packet)?;
|
||||||
self.tparams.reset();
|
self.tparams.reset();
|
||||||
self.tparams.tstate.metadata_params = *metadata_pdu.metadata_params();
|
self.tparams.tstate.metadata_params = *metadata_pdu.metadata_params();
|
||||||
|
let remote_cfg = self
|
||||||
|
.remote_cfg_table
|
||||||
|
.get_remote_config(metadata_pdu.dest_id().value());
|
||||||
|
if remote_cfg.is_none() {
|
||||||
|
return Err(DestError::NoRemoteCfgFound(metadata_pdu.dest_id()));
|
||||||
|
}
|
||||||
|
self.tparams.remote_cfg = Some(*remote_cfg.unwrap());
|
||||||
|
|
||||||
|
// TODO: Support for metadata only PDUs.
|
||||||
let src_name = metadata_pdu.src_file_name();
|
let src_name = metadata_pdu.src_file_name();
|
||||||
if src_name.is_empty() {
|
if src_name.is_empty() {
|
||||||
return Err(DestError::EmptySrcFileField);
|
return Err(DestError::EmptySrcFileField);
|
||||||
@ -332,17 +359,24 @@ impl DestinationHandler {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_if)]
|
|
||||||
pub fn handle_eof_pdu(&mut self, raw_packet: &[u8]) -> Result<(), DestError> {
|
pub fn handle_eof_pdu(&mut self, raw_packet: &[u8]) -> Result<(), DestError> {
|
||||||
if self.state == State::Idle || self.step != TransactionStep::ReceivingFileDataPdus {
|
if self.state == State::Idle || self.step != TransactionStep::ReceivingFileDataPdus {
|
||||||
return Err(DestError::WrongStateForFileDataAndEof);
|
return Err(DestError::WrongStateForFileDataAndEof);
|
||||||
}
|
}
|
||||||
let eof_pdu = EofPdu::from_bytes(raw_packet)?;
|
let eof_pdu = EofPdu::from_bytes(raw_packet)?;
|
||||||
let checksum = eof_pdu.file_checksum();
|
if eof_pdu.condition_code() == ConditionCode::NoError {
|
||||||
|
self.handle_no_error_eof_pdu(&eof_pdu)?;
|
||||||
|
} else {
|
||||||
|
todo!("implement cancel request handling");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_no_error_eof_pdu(&mut self, eof_pdu: &EofPdu) -> Result<(), DestError> {
|
||||||
// For a standard disk based file system, which is assumed to be used for now, the file
|
// For a standard disk based file system, which is assumed to be used for now, the file
|
||||||
// will always be retained. This might change in the future.
|
// will always be retained. This might change in the future.
|
||||||
self.tparams.tstate.file_status = FileStatus::Retained;
|
self.tparams.tstate.file_status = FileStatus::Retained;
|
||||||
if self.checksum_check(checksum)? {
|
if self.checksum_check(eof_pdu.file_checksum())? {
|
||||||
self.tparams.tstate.condition_code = ConditionCode::NoError;
|
self.tparams.tstate.condition_code = ConditionCode::NoError;
|
||||||
self.tparams.tstate.delivery_code = DeliveryCode::Complete;
|
self.tparams.tstate.delivery_code = DeliveryCode::Complete;
|
||||||
} else {
|
} else {
|
||||||
@ -351,7 +385,7 @@ impl DestinationHandler {
|
|||||||
// TODO: Check progress, and implement transfer completion timer as specified in the
|
// TODO: Check progress, and implement transfer completion timer as specified in the
|
||||||
// standard. This timer protects against out of order arrival of packets.
|
// standard. This timer protects against out of order arrival of packets.
|
||||||
if self.tparams.tstate.progress != self.tparams.file_size() {}
|
if self.tparams.tstate.progress != self.tparams.file_size() {}
|
||||||
if self.state == State::Busy {
|
if self.tparams.transmission_mode() == TransmissionMode::Unacknowledged {
|
||||||
self.step = TransactionStep::TransferCompletion;
|
self.step = TransactionStep::TransferCompletion;
|
||||||
} else {
|
} else {
|
||||||
self.step = TransactionStep::SendingAckPdu;
|
self.step = TransactionStep::SendingAckPdu;
|
||||||
@ -364,6 +398,7 @@ impl DestinationHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn checksum_check(&mut self, expected_checksum: u32) -> Result<bool, DestError> {
|
fn checksum_check(&mut self, expected_checksum: u32) -> Result<bool, DestError> {
|
||||||
|
// TODO: Implement this using the new virtual filestore abstraction.
|
||||||
let mut digest = CRC_32.digest();
|
let mut digest = CRC_32.digest();
|
||||||
let file_to_check = File::open(&self.tparams.file_properties.dest_path_buf)?;
|
let file_to_check = File::open(&self.tparams.file_properties.dest_path_buf)?;
|
||||||
let mut buf_reader = BufReader::new(file_to_check);
|
let mut buf_reader = BufReader::new(file_to_check);
|
||||||
@ -492,6 +527,11 @@ impl DestinationHandler {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn declare_fault(&mut self, condition_code: ConditionCode) -> FaultHandlerCode {
|
||||||
|
todo!("implement this. requires cached fault handler abstraction");
|
||||||
|
FaultHandlerCode::IgnoreError
|
||||||
|
}
|
||||||
|
|
||||||
fn reset(&mut self) {
|
fn reset(&mut self) {
|
||||||
self.step = TransactionStep::Idle;
|
self.step = TransactionStep::Idle;
|
||||||
self.state = State::Idle;
|
self.state = State::Idle;
|
||||||
@ -520,12 +560,17 @@ mod tests {
|
|||||||
use alloc::{format, string::String};
|
use alloc::{format, string::String};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use spacepackets::{
|
use spacepackets::{
|
||||||
cfdp::{lv::Lv, pdu::{WritablePduPacket, metadata::MetadataPduCreator}, ChecksumType, TransmissionMode},
|
cfdp::{
|
||||||
|
lv::Lv,
|
||||||
|
pdu::{metadata::MetadataPduCreator, WritablePduPacket},
|
||||||
|
ChecksumType, TransmissionMode,
|
||||||
|
},
|
||||||
util::{UbfU16, UnsignedByteFieldU16},
|
util::{UbfU16, UnsignedByteFieldU16},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::cfdp::{
|
use crate::cfdp::{
|
||||||
CheckTimer, CheckTimerCreator, RemoteEntityConfig, StdRemoteEntityConfigProvider,
|
CheckTimer, CheckTimerCreator, RemoteEntityConfig, StdRemoteEntityConfigProvider,
|
||||||
|
UserFaultHandler,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -553,6 +598,47 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct TestFaultHandler {
|
||||||
|
notice_of_suspension_count: u32,
|
||||||
|
notice_of_cancellation_count: u32,
|
||||||
|
abandoned_count: u32,
|
||||||
|
ignored_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserFaultHandler for TestFaultHandler {
|
||||||
|
fn notice_of_suspension_cb(
|
||||||
|
&mut self,
|
||||||
|
transaction_id: TransactionId,
|
||||||
|
cond: ConditionCode,
|
||||||
|
progress: u64,
|
||||||
|
) {
|
||||||
|
self.notice_of_suspension_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn notice_of_cancellation_cb(
|
||||||
|
&mut self,
|
||||||
|
transaction_id: TransactionId,
|
||||||
|
cond: ConditionCode,
|
||||||
|
progress: u64,
|
||||||
|
) {
|
||||||
|
self.notice_of_cancellation_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn abandoned_cb(
|
||||||
|
&mut self,
|
||||||
|
transaction_id: TransactionId,
|
||||||
|
cond: ConditionCode,
|
||||||
|
progress: u64,
|
||||||
|
) {
|
||||||
|
self.abandoned_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ignore_cb(&mut self, transaction_id: TransactionId, cond: ConditionCode, progress: u64) {
|
||||||
|
self.ignored_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CfdpUser for TestCfdpUser {
|
impl CfdpUser for TestCfdpUser {
|
||||||
fn transaction_indication(&mut self, id: &crate::cfdp::TransactionId) {
|
fn transaction_indication(&mut self, id: &crate::cfdp::TransactionId) {
|
||||||
self.generic_id_check(id);
|
self.generic_id_check(id);
|
||||||
@ -719,8 +805,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn default_dest_handler() -> DestinationHandler {
|
fn default_dest_handler() -> DestinationHandler {
|
||||||
|
let test_fault_handler = TestFaultHandler::default();
|
||||||
DestinationHandler::new(
|
DestinationHandler::new(
|
||||||
REMOTE_ID,
|
REMOTE_ID,
|
||||||
|
Box::new(NativeFilestore::default()),
|
||||||
|
DefaultFaultHandler::new(Box::new(test_fault_handler)),
|
||||||
Box::new(basic_remote_cfg_table()),
|
Box::new(basic_remote_cfg_table()),
|
||||||
Box::new(TestCheckTimerCreator::new(2, 2)),
|
Box::new(TestCheckTimerCreator::new(2, 2)),
|
||||||
)
|
)
|
||||||
|
@ -141,6 +141,7 @@ pub mod stdmod {
|
|||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct NativeFilestore {}
|
pub struct NativeFilestore {}
|
||||||
|
|
||||||
impl VirtualFilestore for NativeFilestore {
|
impl VirtualFilestore for NativeFilestore {
|
||||||
|
@ -5,7 +5,7 @@ use hashbrown::HashMap;
|
|||||||
use spacepackets::{
|
use spacepackets::{
|
||||||
cfdp::{
|
cfdp::{
|
||||||
pdu::{FileDirectiveType, PduError, PduHeader},
|
pdu::{FileDirectiveType, PduError, PduHeader},
|
||||||
ChecksumType, PduType, TransmissionMode,
|
ChecksumType, ConditionCode, FaultHandlerCode, PduType, TransmissionMode,
|
||||||
},
|
},
|
||||||
util::UnsignedByteField,
|
util::UnsignedByteField,
|
||||||
};
|
};
|
||||||
@ -161,6 +161,103 @@ impl RemoteEntityConfigProvider for StdRemoteEntityConfigProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This trait introduces some callbacks which will be called when a particular CFDP fault
|
||||||
|
/// handler is called. This allows to implement some CFDP features like fault handler logging,
|
||||||
|
/// which would not be possible generically otherwise.
|
||||||
|
pub trait UserFaultHandler {
|
||||||
|
fn notice_of_suspension_cb(
|
||||||
|
&mut self,
|
||||||
|
transaction_id: TransactionId,
|
||||||
|
cond: ConditionCode,
|
||||||
|
progress: u64,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn notice_of_cancellation_cb(
|
||||||
|
&mut self,
|
||||||
|
transaction_id: TransactionId,
|
||||||
|
cond: ConditionCode,
|
||||||
|
progress: u64,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn abandoned_cb(&mut self, transaction_id: TransactionId, cond: ConditionCode, progress: u64);
|
||||||
|
|
||||||
|
fn ignore_cb(&mut self, transaction_id: TransactionId, cond: ConditionCode, progress: u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DefaultFaultHandler {
|
||||||
|
handler_array: [FaultHandlerCode; 10],
|
||||||
|
user_fault_handler: Box<dyn UserFaultHandler + Send>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DefaultFaultHandler {
|
||||||
|
fn condition_code_to_array_index(conditon_code: ConditionCode) -> Option<usize> {
|
||||||
|
Some(match conditon_code {
|
||||||
|
ConditionCode::PositiveAckLimitReached => 0,
|
||||||
|
ConditionCode::KeepAliveLimitReached => 1,
|
||||||
|
ConditionCode::InvalidTransmissionMode => 2,
|
||||||
|
ConditionCode::FilestoreRejection => 3,
|
||||||
|
ConditionCode::FileChecksumFailure => 4,
|
||||||
|
ConditionCode::FileSizeError => 5,
|
||||||
|
ConditionCode::NakLimitReached => 6,
|
||||||
|
ConditionCode::InactivityDetected => 7,
|
||||||
|
ConditionCode::CheckLimitReached => 8,
|
||||||
|
ConditionCode::UnsupportedChecksumType => 9,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(user_fault_handler: Box<dyn UserFaultHandler + Send>) -> Self {
|
||||||
|
let mut init_array = [FaultHandlerCode::NoticeOfCancellation; 10];
|
||||||
|
init_array
|
||||||
|
[Self::condition_code_to_array_index(ConditionCode::FileChecksumFailure).unwrap()] =
|
||||||
|
FaultHandlerCode::IgnoreError;
|
||||||
|
init_array[Self::condition_code_to_array_index(ConditionCode::UnsupportedChecksumType)
|
||||||
|
.unwrap()] = FaultHandlerCode::IgnoreError;
|
||||||
|
Self {
|
||||||
|
handler_array: init_array,
|
||||||
|
user_fault_handler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_fault(
|
||||||
|
&mut self,
|
||||||
|
transaction_id: TransactionId,
|
||||||
|
condition: ConditionCode,
|
||||||
|
progress: u64,
|
||||||
|
) -> FaultHandlerCode {
|
||||||
|
let array_idx = Self::condition_code_to_array_index(condition);
|
||||||
|
if array_idx.is_none() {
|
||||||
|
return FaultHandlerCode::IgnoreError;
|
||||||
|
}
|
||||||
|
let fh_code = self.handler_array[array_idx.unwrap()];
|
||||||
|
match fh_code {
|
||||||
|
FaultHandlerCode::NoticeOfCancellation => {
|
||||||
|
self.user_fault_handler.notice_of_cancellation_cb(
|
||||||
|
transaction_id,
|
||||||
|
condition,
|
||||||
|
progress,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
FaultHandlerCode::NoticeOfSuspension => {
|
||||||
|
self.user_fault_handler.notice_of_suspension_cb(
|
||||||
|
transaction_id,
|
||||||
|
condition,
|
||||||
|
progress,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
FaultHandlerCode::IgnoreError => {
|
||||||
|
self.user_fault_handler
|
||||||
|
.ignore_cb(transaction_id, condition, progress);
|
||||||
|
}
|
||||||
|
FaultHandlerCode::AbandonTransaction => {
|
||||||
|
self.user_fault_handler
|
||||||
|
.abandoned_cb(transaction_id, condition, progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fh_code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, Copy, Clone)]
|
#[derive(Debug, Eq, Copy, Clone)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct TransactionId {
|
pub struct TransactionId {
|
||||||
@ -347,7 +444,8 @@ mod tests {
|
|||||||
let dest_file_name = "hello-dest.txt";
|
let dest_file_name = "hello-dest.txt";
|
||||||
let src_lv = Lv::new_from_str(src_file_name).unwrap();
|
let src_lv = Lv::new_from_str(src_file_name).unwrap();
|
||||||
let dest_lv = Lv::new_from_str(dest_file_name).unwrap();
|
let dest_lv = Lv::new_from_str(dest_file_name).unwrap();
|
||||||
let metadata_pdu = MetadataPduCreator::new_no_opts(pdu_header, metadata_params, src_lv, dest_lv);
|
let metadata_pdu =
|
||||||
|
MetadataPduCreator::new_no_opts(pdu_header, metadata_params, src_lv, dest_lv);
|
||||||
metadata_pdu
|
metadata_pdu
|
||||||
.write_to_bytes(&mut buf)
|
.write_to_bytes(&mut buf)
|
||||||
.expect("writing metadata PDU failed");
|
.expect("writing metadata PDU failed");
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use spacepackets::ecss::{Ptc, PfcReal, PfcUnsigned};
|
use spacepackets::ecss::{PfcReal, PfcUnsigned, Ptc};
|
||||||
use spacepackets::time::cds::TimeProvider;
|
use spacepackets::time::cds::TimeProvider;
|
||||||
use spacepackets::time::{CcsdsTimeProvider, TimeWriter};
|
use spacepackets::time::{CcsdsTimeProvider, TimeWriter};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user