Continue update
Some checks failed
Rust/sat-rs/pipeline/pr-main There was a failure building this commit

This commit is contained in:
Robin Müller 2024-04-02 09:55:30 +02:00
parent 5c1acfe912
commit bc04275763
Signed by: muellerr
GPG Key ID: A649FB78196E3849
44 changed files with 3384 additions and 3437 deletions

View File

@ -18,14 +18,15 @@ csv = "1"
num_enum = "0.7" num_enum = "0.7"
thiserror = "1" thiserror = "1"
derive-new = "0.5" derive-new = "0.5"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
[dependencies.satrs] [dependencies.satrs]
# version = "0.2.0-rc.0"
path = "../satrs" path = "../satrs"
features = ["test_util"] features = ["test_util"]
[dependencies.satrs-mib] [dependencies.satrs-mib]
# version = "0.1.1" version = "0.1.1"
path = "../satrs-mib" path = "../satrs-mib"
[features] [features]

View File

@ -1,44 +1,123 @@
// TODO: Remove this at a later stage. // TODO: Remove this at a later stage.
#![allow(dead_code)] #![allow(dead_code)]
use derive_new::new;
use satrs::hk::HkRequestVariant;
use satrs::spacepackets::ecss::hk;
use satrs::spacepackets::ecss::tm::{PusTmCreator, PusTmSecondaryHeader};
use satrs::spacepackets::SpHeader;
use satrs_example::TimeStampHelper;
use std::sync::mpsc::{self}; use std::sync::mpsc::{self};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use satrs::mode::{ModeAndSubmode, ModeProvider, ModeReply, ModeRequest, ModeRequestHandler}; use satrs::mode::{ModeAndSubmode, ModeProvider, ModeReply, ModeRequest, ModeRequestHandler};
use satrs::pus::EcssTmSenderCore; use satrs::pus::{EcssTmSenderCore, PusTmVariant};
use satrs::request::GenericMessage; use satrs::request::{GenericMessage, MessageMetadata, UniqueApidTargetId};
use satrs::ComponentId; use satrs::ComponentId;
use satrs_example::config::components::PUS_MODE_SERVICE;
use crate::pus::hk::HkReply; use crate::pus::hk::{HkReply, HkReplyVariant};
use crate::requests::CompositeRequest; use crate::requests::CompositeRequest;
use serde::{Deserialize, Serialize};
pub trait SpiInterface { pub trait SpiInterface {
type Error; type Error;
fn transfer(&mut self, data: &mut [u8]) -> Result<(), Self::Error>; fn transfer(&mut self, data: &mut [u8]) -> Result<(), Self::Error>;
} }
#[derive(Debug, Copy, Clone)] #[derive(Default)]
pub struct SpiDummyInterface {}
impl SpiInterface for SpiDummyInterface {
type Error = ();
fn transfer(&mut self, _data: &mut [u8]) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize)]
pub struct MgmData { pub struct MgmData {
pub x: f32, pub x: f32,
pub y: f32, pub y: f32,
pub z: f32, pub z: f32,
} }
#[derive(new)]
pub struct MgmHandler<ComInterface: SpiInterface, TmSender: EcssTmSenderCore> { pub struct MgmHandler<ComInterface: SpiInterface, TmSender: EcssTmSenderCore> {
id: ComponentId, id: UniqueApidTargetId,
dev_str: &'static str, dev_str: &'static str,
mode_request_receiver: mpsc::Receiver<GenericMessage<ModeRequest>>, mode_request_receiver: mpsc::Receiver<GenericMessage<ModeRequest>>,
composite_request_receiver: mpsc::Receiver<GenericMessage<CompositeRequest>>,
mode_reply_sender_to_pus: mpsc::Sender<GenericMessage<ModeReply>>, mode_reply_sender_to_pus: mpsc::Sender<GenericMessage<ModeReply>>,
mode_reply_sender_to_parent: mpsc::Sender<GenericMessage<ModeReply>>, mode_reply_sender_to_parent: mpsc::Sender<GenericMessage<ModeReply>>,
composite_request_receiver: mpsc::Receiver<GenericMessage<CompositeRequest>>,
hk_reply_sender: mpsc::Sender<GenericMessage<HkReply>>, hk_reply_sender: mpsc::Sender<GenericMessage<HkReply>>,
hk_tm_sender: TmSender, hk_tm_sender: TmSender,
mode: ModeAndSubmode,
spi_interface: ComInterface, spi_interface: ComInterface,
shared_mgm_set: Arc<Mutex<MgmData>>, shared_mgm_set: Arc<Mutex<MgmData>>,
#[new(value = "ModeAndSubmode::new(satrs_example::DeviceMode::Off as u32, 0)")]
mode: ModeAndSubmode,
#[new(default)]
stamp_helper: TimeStampHelper,
} }
impl<ComInterface: SpiInterface, TmSender: EcssTmSenderCore> MgmHandler<ComInterface, TmSender> { impl<ComInterface: SpiInterface, TmSender: EcssTmSenderCore> MgmHandler<ComInterface, TmSender> {
pub fn perform_operation(&mut self) {} pub fn periodic_operation(&mut self) {
self.stamp_helper.update_from_now();
// Handle messages.
match self.composite_request_receiver.try_recv() {
Ok(ref msg) => match &msg.message {
CompositeRequest::Hk(hk_req) => match hk_req.variant {
HkRequestVariant::OneShot => {
self.hk_reply_sender
.send(GenericMessage::new(
msg.requestor_info,
HkReply::new(hk_req.unique_id, HkReplyVariant::Ack),
))
.expect("failed to send HK reply");
let mut sp_header = SpHeader::tm_unseg(self.id.apid, 0, 0).unwrap();
let sec_header = PusTmSecondaryHeader::new(
3,
hk::Subservice::TmHkPacket as u8,
0,
0,
Some(self.stamp_helper.stamp()),
);
// Let's serialize it as JSON for now.. This is a lot simpler than binary
// serialization.
let mgm_data_serialized =
serde_json::to_vec(&*self.shared_mgm_set.lock().unwrap()).unwrap();
let hk_tm = PusTmCreator::new(
&mut sp_header,
sec_header,
&mgm_data_serialized,
true,
);
self.hk_tm_sender
.send_tm(self.id.id(), PusTmVariant::Direct(hk_tm))
.expect("failed to send HK TM");
}
HkRequestVariant::EnablePeriodic => todo!(),
HkRequestVariant::DisablePeriodic => todo!(),
HkRequestVariant::ModifyCollectionInterval(_) => todo!(),
},
// This object does not have actions (yet).. Still send back completion failure
// reply.
CompositeRequest::Action(action_req) => {}
},
Err(_) => todo!(),
}
match self.mode_request_receiver.try_recv() {
Ok(msg) => match msg.message {
ModeRequest::SetMode(_) => todo!(),
ModeRequest::ReadMode => todo!(),
ModeRequest::AnnounceMode => todo!(),
ModeRequest::AnnounceModeRecursive => todo!(),
ModeRequest::ModeInfo(_) => todo!(),
},
Err(_) => todo!(),
}
}
} }
impl<ComInterface: SpiInterface, TmSender: EcssTmSenderCore> ModeProvider impl<ComInterface: SpiInterface, TmSender: EcssTmSenderCore> ModeProvider
@ -54,23 +133,37 @@ impl<ComInterface: SpiInterface, TmSender: EcssTmSenderCore> ModeRequestHandler
{ {
fn start_transition( fn start_transition(
&mut self, &mut self,
request_id: satrs::request::RequestId, requestor: MessageMetadata,
sender_id: ComponentId,
mode_and_submode: ModeAndSubmode, mode_and_submode: ModeAndSubmode,
) -> Result<(), satrs::mode::ModeError> { ) -> Result<(), satrs::mode::ModeError> {
todo!() self.mode = mode_and_submode;
self.handle_mode_reached(Some(requestor))?;
Ok(())
} }
fn announce_mode( fn announce_mode(&self, _requestor_info: MessageMetadata, _recursive: bool) {
&self,
request_id: satrs::request::RequestId,
sender_id: satrs::ComponentId,
recursive: bool,
) {
log::info!("{} announcing mode: {:?}", self.dev_str, self.mode); log::info!("{} announcing mode: {:?}", self.dev_str, self.mode);
} }
fn handle_mode_reached(&mut self) -> Result<(), satrs::queue::GenericTargetedMessagingError> { fn handle_mode_reached(
todo!() &mut self,
requestor: Option<MessageMetadata>,
) -> Result<(), satrs::queue::GenericTargetedMessagingError> {
if let Some(requestor) = requestor {
if requestor.sender_id() == PUS_MODE_SERVICE.raw() {
// self.mode_reply_sender_to_pus.send(
//GenericMessage::new(requestor.request_id, requestor.sender_id, ModeReply::ModeReply(self.mode))
// )?;
}
}
Ok(())
}
fn send_mode_reply(
&self,
_requestor: MessageMetadata,
_reply: ModeReply,
) -> Result<(), satrs::queue::GenericTargetedMessagingError> {
Ok(())
} }
} }

View File

@ -1,9 +1,9 @@
mod mgm; pub mod mgm;
/* /*
pub struct AcsTask<VerificationReporter: VerificationReportingProvider> { pub struct AcsTask<VerificationReporter: VerificationReportingProvider> {
timestamp: [u8; 7], timestamp: [u8; 7],
time_provider: TimeProvider<DaysLen16Bits>, time_provider: CdsTime<DaysLen16Bits>,
verif_reporter: VerificationReporter, verif_reporter: VerificationReporter,
tm_sender: Box<dyn EcssTmSender>, tm_sender: Box<dyn EcssTmSender>,
request_rx: mpsc::Receiver<RequestWithToken>, request_rx: mpsc::Receiver<RequestWithToken>,
@ -17,7 +17,7 @@ impl<VerificationReporter: VerificationReportingProvider> AcsTask<VerificationRe
) -> Self { ) -> Self {
Self { Self {
timestamp: [0; 7], timestamp: [0; 7],
time_provider: TimeProvider::new_with_u16_days(0, 0), time_provider: CdsTime::new_with_u16_days(0, 0),
verif_reporter, verif_reporter,
tm_sender: Box::new(tm_sender), tm_sender: Box::new(tm_sender),
request_rx, request_rx,

View File

@ -1,7 +1,7 @@
use satrs::pus::ReceivesEcssPusTc; use satrs::pus::ReceivesEcssPusTc;
use satrs::spacepackets::{CcsdsPacket, SpHeader}; use satrs::spacepackets::{CcsdsPacket, SpHeader};
use satrs::tmtc::{CcsdsPacketHandler, ReceivesCcsdsTc}; use satrs::tmtc::{CcsdsPacketHandler, ReceivesCcsdsTc};
use satrs_example::config::PUS_APID; use satrs_example::config::components::Apid;
#[derive(Clone)] #[derive(Clone)]
pub struct CcsdsReceiver< pub struct CcsdsReceiver<
@ -19,7 +19,12 @@ impl<
type Error = E; type Error = E;
fn valid_apids(&self) -> &'static [u16] { fn valid_apids(&self) -> &'static [u16] {
&[PUS_APID] &[
Apid::GenericPus as u16,
Apid::Acs as u16,
Apid::Sched as u16,
Apid::EventTm as u16,
]
} }
fn handle_known_apid( fn handle_known_apid(
@ -27,7 +32,8 @@ impl<
sp_header: &SpHeader, sp_header: &SpHeader,
tc_raw: &[u8], tc_raw: &[u8],
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
if sp_header.apid() == PUS_APID { if sp_header.apid() == Apid::Cfdp as u16 {
} else {
return self.tc_source.pass_ccsds(sp_header, tc_raw); return self.tc_source.pass_ccsds(sp_header, tc_raw);
} }
Ok(()) Ok(())

View File

@ -9,8 +9,6 @@ use satrs::{
pool::{StaticMemoryPool, StaticPoolConfig}, pool::{StaticMemoryPool, StaticPoolConfig},
}; };
pub const PUS_APID: u16 = 0x02;
#[derive(Copy, Clone, PartialEq, Eq, Debug, TryFromPrimitive, IntoPrimitive)] #[derive(Copy, Clone, PartialEq, Eq, Debug, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)] #[repr(u8)]
pub enum CustomPusServiceId { pub enum CustomPusServiceId {
@ -102,14 +100,51 @@ pub mod mode_err {
pub const WRONG_MODE: ResultU16 = ResultU16::new(GroupId::Mode as u8, 0); pub const WRONG_MODE: ResultU16 = ResultU16::new(GroupId::Mode as u8, 0);
} }
#[derive(Copy, Clone, PartialEq, Eq)] pub mod components {
pub enum ComponentIdList { use satrs::request::UniqueApidTargetId;
PusVerification = 0,
EventManagement = 1, #[derive(Copy, Clone, PartialEq, Eq)]
PusTest = 2, pub enum Apid {
PusAction = 3, VerificationTm = 1,
PusSched = 4, Sched = 2,
PusHk = 5, EventTm = 3,
HkTm = 4,
GenericPus = 5,
Acs = 6,
Cfdp = 7,
}
// Component IDs for components with the PUS APID.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum PusId {
PusRouting = 0,
PusTest = 1,
PusAction = 2,
PusMode = 3,
PusHk = 4,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum AcsId {
Mgm0 = 0,
}
pub const PUS_ACTION_SERVICE: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusAction as u32);
pub const PUS_EVENT_MANAGEMENT: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::EventTm as u16, 0);
pub const PUS_ROUTING_SERVICE: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusRouting as u32);
pub const PUS_TEST_SERVICE: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusTest as u32);
pub const PUS_MODE_SERVICE: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusMode as u32);
pub const PUS_HK_SERVICE: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusHk as u32);
pub const PUS_SCHED_SERVICE: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Sched as u16, 0);
pub const MGM_HANDLER_0: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Acs as u16, AcsId::Mgm0 as u32);
} }
pub mod pool { pub mod pool {

View File

@ -1,5 +1,8 @@
use std::sync::mpsc::{self}; use std::sync::mpsc::{self};
use crate::pus::create_verification_reporter;
use satrs::pus::verification::VerificationReporter;
use satrs::pus::EcssTmSenderCore;
use satrs::{ use satrs::{
event_man::{ event_man::{
EventManagerWithBoundedMpsc, EventSendProvider, EventU32SenderMpscBounded, EventManagerWithBoundedMpsc, EventSendProvider, EventU32SenderMpscBounded,
@ -12,44 +15,51 @@ use satrs::{
DefaultPusEventU32Dispatcher, EventReporter, EventRequest, EventRequestWithToken, DefaultPusEventU32Dispatcher, EventReporter, EventRequest, EventRequestWithToken,
}, },
verification::{TcStateStarted, VerificationReportingProvider, VerificationToken}, verification::{TcStateStarted, VerificationReportingProvider, VerificationToken},
EcssTmSender,
}, },
spacepackets::time::cds::{self, TimeProvider}, spacepackets::time::cds::CdsTime,
ComponentId, ComponentId,
}; };
use satrs_example::config::{ComponentIdList, PUS_APID}; use satrs_example::config::components;
use satrs_example::config::components::PUS_EVENT_MANAGEMENT;
use crate::update_time; use crate::update_time;
/// The PUS event handler subscribes for all events and converts them into ECSS PUS 5 event /// The PUS event handler subscribes for all events and converts them into ECSS PUS 5 event
/// packets. It also handles the verification completion of PUS event service requests. /// packets. It also handles the verification completion of PUS event service requests.
pub struct PusEventHandler<VerificationReporter: VerificationReportingProvider> { pub struct PusEventHandler<TmSender: EcssTmSenderCore> {
id: ComponentId,
event_request_rx: mpsc::Receiver<EventRequestWithToken>, event_request_rx: mpsc::Receiver<EventRequestWithToken>,
pus_event_dispatcher: DefaultPusEventU32Dispatcher<()>, pus_event_dispatcher: DefaultPusEventU32Dispatcher<()>,
pus_event_man_rx: mpsc::Receiver<(EventU32, Option<Params>)>, pus_event_man_rx: mpsc::Receiver<(EventU32, Option<Params>)>,
tm_sender: Box<dyn EcssTmSender>, tm_sender: TmSender,
time_provider: TimeProvider, time_provider: CdsTime,
timestamp: [u8; 7], timestamp: [u8; 7],
verif_handler: VerificationReporter, verif_handler: VerificationReporter,
} }
impl<VerificationReporter: VerificationReportingProvider> PusEventHandler<VerificationReporter> { impl<TmSender: EcssTmSenderCore> PusEventHandler<TmSender> {
pub fn new( pub fn new(
id: ComponentId,
tm_sender: TmSender,
verif_handler: VerificationReporter, verif_handler: VerificationReporter,
event_manager: &mut EventManagerWithBoundedMpsc, event_manager: &mut EventManagerWithBoundedMpsc,
event_request_rx: mpsc::Receiver<EventRequestWithToken>, event_request_rx: mpsc::Receiver<EventRequestWithToken>,
tm_sender: impl EcssTmSender,
) -> Self { ) -> Self {
let event_queue_cap = 30; let event_queue_cap = 30;
let (pus_event_man_tx, pus_event_man_rx) = mpsc::sync_channel(event_queue_cap); let (pus_event_man_tx, pus_event_man_rx) = mpsc::sync_channel(event_queue_cap);
// All events sent to the manager are routed to the PUS event manager, which generates PUS event // All events sent to the manager are routed to the PUS event manager, which generates PUS event
// telemetry for each event. // telemetry for each event.
let event_reporter = EventReporter::new(PUS_APID, 128).unwrap(); let event_reporter = EventReporter::new(
PUS_EVENT_MANAGEMENT.raw(),
components::Apid::EventTm as u16,
128,
)
.unwrap();
let pus_event_dispatcher = let pus_event_dispatcher =
DefaultPusEventU32Dispatcher::new_with_default_backend(event_reporter); DefaultPusEventU32Dispatcher::new_with_default_backend(event_reporter);
let pus_event_man_send_provider = EventU32SenderMpscBounded::new( let pus_event_man_send_provider = EventU32SenderMpscBounded::new(
ComponentIdList::EventManagement as ComponentId, PUS_EVENT_MANAGEMENT.raw(),
pus_event_man_tx, pus_event_man_tx,
event_queue_cap, event_queue_cap,
); );
@ -58,13 +68,14 @@ impl<VerificationReporter: VerificationReportingProvider> PusEventHandler<Verifi
event_manager.add_sender(pus_event_man_send_provider); event_manager.add_sender(pus_event_man_send_provider);
Self { Self {
id,
event_request_rx, event_request_rx,
pus_event_dispatcher, pus_event_dispatcher,
pus_event_man_rx, pus_event_man_rx,
time_provider: cds::TimeProvider::new_with_u16_days(0, 0), time_provider: CdsTime::new_with_u16_days(0, 0),
timestamp: [0; 7], timestamp: [0; 7],
verif_handler, verif_handler,
tm_sender: Box::new(tm_sender), tm_sender,
} }
} }
@ -75,7 +86,7 @@ impl<VerificationReporter: VerificationReportingProvider> PusEventHandler<Verifi
.try_into() .try_into()
.expect("expected start verification token"); .expect("expected start verification token");
self.verif_handler self.verif_handler
.completion_success(started_token, timestamp) .completion_success(self.id, &self.tm_sender, started_token, timestamp)
.expect("Sending completion success failed"); .expect("Sending completion success failed");
}; };
// handle event requests // handle event requests
@ -104,12 +115,7 @@ impl<VerificationReporter: VerificationReportingProvider> PusEventHandler<Verifi
if let Ok((event, _param)) = self.pus_event_man_rx.try_recv() { if let Ok((event, _param)) = self.pus_event_man_rx.try_recv() {
update_time(&mut self.time_provider, &mut self.timestamp); update_time(&mut self.time_provider, &mut self.timestamp);
self.pus_event_dispatcher self.pus_event_dispatcher
.generate_pus_event_tm_generic( .generate_pus_event_tm_generic(&mut self.tm_sender, &self.timestamp, event, None)
self.tm_sender.upcast_mut(),
&self.timestamp,
event,
None,
)
.expect("Sending TM as event failed"); .expect("Sending TM as event failed");
} }
} }
@ -151,23 +157,23 @@ impl EventManagerWrapper {
} }
} }
pub struct EventHandler<VerificationReporter: VerificationReportingProvider> { pub struct EventHandler<TmSender: EcssTmSenderCore> {
pub event_man_wrapper: EventManagerWrapper, pub event_man_wrapper: EventManagerWrapper,
pub pus_event_handler: PusEventHandler<VerificationReporter>, pub pus_event_handler: PusEventHandler<TmSender>,
} }
impl<VerificationReporter: VerificationReportingProvider> EventHandler<VerificationReporter> { impl<TmSender: EcssTmSenderCore> EventHandler<TmSender> {
pub fn new( pub fn new(
tm_sender: impl EcssTmSender, tm_sender: TmSender,
verif_handler: VerificationReporter,
event_request_rx: mpsc::Receiver<EventRequestWithToken>, event_request_rx: mpsc::Receiver<EventRequestWithToken>,
) -> Self { ) -> Self {
let mut event_man_wrapper = EventManagerWrapper::new(); let mut event_man_wrapper = EventManagerWrapper::new();
let pus_event_handler = PusEventHandler::new( let pus_event_handler = PusEventHandler::new(
verif_handler, PUS_EVENT_MANAGEMENT.raw(),
tm_sender,
create_verification_reporter(PUS_EVENT_MANAGEMENT.apid),
event_man_wrapper.event_manager(), event_man_wrapper.event_manager(),
event_request_rx, event_request_rx,
tm_sender,
); );
Self { Self {
event_man_wrapper, event_man_wrapper,

View File

@ -1,27 +1,25 @@
use derive_new::new; use derive_new::new;
use satrs::hk::UniqueId;
use satrs::request::UniqueApidTargetId;
use satrs::spacepackets::ByteConversionError; use satrs::spacepackets::ByteConversionError;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AcsHkIds {
TestMgmSet = 1,
}
#[derive(Debug, new, Copy, Clone)] #[derive(Debug, new, Copy, Clone)]
pub struct HkUniqueId { pub struct HkUniqueId {
target_id: u32, target_id: UniqueApidTargetId,
set_id: u32, set_id: UniqueId,
} }
impl HkUniqueId { impl HkUniqueId {
#[allow(dead_code)] #[allow(dead_code)]
pub fn target_id(&self) -> u32 { pub fn target_id(&self) -> UniqueApidTargetId {
self.target_id self.target_id
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn set_id(&self) -> u32 { pub fn set_id(&self) -> UniqueId {
self.set_id self.set_id
} }
#[allow(dead_code)]
pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> { pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
if buf.len() < 8 { if buf.len() < 8 {
return Err(ByteConversionError::ToSliceTooSmall { return Err(ByteConversionError::ToSliceTooSmall {
@ -29,7 +27,7 @@ impl HkUniqueId {
expected: 8, expected: 8,
}); });
} }
buf[0..4].copy_from_slice(&self.target_id.to_be_bytes()); buf[0..4].copy_from_slice(&self.target_id.unique_id.to_be_bytes());
buf[4..8].copy_from_slice(&self.set_id.to_be_bytes()); buf[4..8].copy_from_slice(&self.set_id.to_be_bytes());
Ok(8) Ok(8)

View File

@ -1 +1,39 @@
use satrs::spacepackets::time::{cds::CdsTime, TimeWriter};
pub mod config; pub mod config;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum DeviceMode {
Off = 0,
On = 1,
Normal = 2,
}
pub struct TimeStampHelper {
stamper: CdsTime,
time_stamp: [u8; 7],
}
impl TimeStampHelper {
pub fn stamp(&self) -> &[u8] {
&self.time_stamp
}
pub fn update_from_now(&mut self) {
self.stamper
.update_from_now()
.expect("Updating timestamp failed");
self.stamper
.write_to_bytes(&mut self.time_stamp)
.expect("Writing timestamp failed");
}
}
impl Default for TimeStampHelper {
fn default() -> Self {
Self {
stamper: CdsTime::now_with_u16_days().expect("creating time stamper failed"),
time_stamp: Default::default(),
}
}
}

View File

@ -17,24 +17,23 @@ use log::info;
use pus::test::create_test_service_dynamic; use pus::test::create_test_service_dynamic;
use satrs::hal::std::tcp_server::ServerConfig; use satrs::hal::std::tcp_server::ServerConfig;
use satrs::hal::std::udp_server::UdpTcServer; use satrs::hal::std::udp_server::UdpTcServer;
use satrs::request::{GenericMessage, TargetAndApidId}; use satrs::request::GenericMessage;
use satrs::tmtc::tm_helper::SharedTmPool; use satrs::tmtc::tm_helper::SharedTmPool;
use satrs_example::config::pool::{create_sched_tc_pool, create_static_pools}; use satrs_example::config::pool::{create_sched_tc_pool, create_static_pools};
use satrs_example::config::tasks::{ use satrs_example::config::tasks::{
FREQ_MS_AOCS, FREQ_MS_EVENT_HANDLING, FREQ_MS_PUS_STACK, FREQ_MS_UDP_TMTC, FREQ_MS_AOCS, FREQ_MS_EVENT_HANDLING, FREQ_MS_PUS_STACK, FREQ_MS_UDP_TMTC,
}; };
use satrs_example::config::{ use satrs_example::config::{OBSW_SERVER_ADDR, SERVER_PORT};
ComponentIdList, RequestTargetId, OBSW_SERVER_ADDR, PUS_APID, SERVER_PORT,
};
use tmtc::PusTcSourceProviderDynamic; use tmtc::PusTcSourceProviderDynamic;
use udp::DynamicUdpTmHandler; use udp::DynamicUdpTmHandler;
// use crate::acs::AcsTask; use crate::acs::mgm::{MgmHandler, SpiDummyInterface};
use crate::ccsds::CcsdsReceiver; use crate::ccsds::CcsdsReceiver;
use crate::logger::setup_logger; use crate::logger::setup_logger;
use crate::pus::action::{create_action_service_dynamic, create_action_service_static}; use crate::pus::action::{create_action_service_dynamic, create_action_service_static};
use crate::pus::event::{create_event_service_dynamic, create_event_service_static}; use crate::pus::event::{create_event_service_dynamic, create_event_service_static};
use crate::pus::hk::{create_hk_service_dynamic, create_hk_service_static}; use crate::pus::hk::{create_hk_service_dynamic, create_hk_service_static};
use crate::pus::mode::{create_mode_service_dynamic, create_mode_service_static};
use crate::pus::scheduler::{create_scheduler_service_dynamic, create_scheduler_service_static}; use crate::pus::scheduler::{create_scheduler_service_dynamic, create_scheduler_service_static};
use crate::pus::test::create_test_service_static; use crate::pus::test::create_test_service_static;
use crate::pus::{PusReceiver, PusTcMpscRouter}; use crate::pus::{PusReceiver, PusTcMpscRouter};
@ -44,27 +43,18 @@ use crate::tmtc::{
PusTcSourceProviderSharedPool, SharedTcPool, TcSourceTaskDynamic, TcSourceTaskStatic, PusTcSourceProviderSharedPool, SharedTcPool, TcSourceTaskDynamic, TcSourceTaskStatic,
}; };
use crate::udp::{StaticUdpTmHandler, UdpTmtcServer}; use crate::udp::{StaticUdpTmHandler, UdpTmtcServer};
use satrs::mode::ModeRequest;
use satrs::pus::event_man::EventRequestWithToken; use satrs::pus::event_man::EventRequestWithToken;
use satrs::pus::verification::{VerificationReporterCfg, VerificationReporterWithSender}; use satrs::pus::TmInSharedPoolSender;
use satrs::pus::{EcssTmSender, TmAsVecSenderWithId, TmInSharedPoolSenderWithId}; use satrs::spacepackets::{time::cds::CdsTime, time::TimeWriter};
use satrs::spacepackets::{time::cds::TimeProvider, time::TimeWriter};
use satrs::tmtc::CcsdsDistributor; use satrs::tmtc::CcsdsDistributor;
use satrs::ComponentId; use satrs_example::config::components::MGM_HANDLER_0;
use std::net::{IpAddr, SocketAddr}; use std::net::{IpAddr, SocketAddr};
use std::sync::mpsc::{self, channel}; use std::sync::mpsc;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
fn create_verification_reporter<Sender: EcssTmSender + Clone>(
verif_sender: Sender,
) -> VerificationReporterWithSender<Sender> {
let verif_cfg = VerificationReporterCfg::new(PUS_APID, 1, 2, 8).unwrap();
// Every software component which needs to generate verification telemetry, gets a cloned
// verification reporter.
VerificationReporterWithSender::new(&verif_cfg, verif_sender)
}
#[allow(dead_code)] #[allow(dead_code)]
fn static_tmtc_pool_main() { fn static_tmtc_pool_main() {
let (tm_pool, tc_pool) = create_static_pools(); let (tm_pool, tc_pool) = create_static_pools();
@ -76,20 +66,21 @@ fn static_tmtc_pool_main() {
let (tm_funnel_tx, tm_funnel_rx) = mpsc::sync_channel(50); let (tm_funnel_tx, tm_funnel_rx) = mpsc::sync_channel(50);
let (tm_server_tx, tm_server_rx) = mpsc::sync_channel(50); let (tm_server_tx, tm_server_rx) = mpsc::sync_channel(50);
// Every software component which needs to generate verification telemetry, receives a cloned let tm_funnel_tx_sender =
// verification reporter. TmInSharedPoolSender::new(shared_tm_pool.clone(), tm_funnel_tx.clone());
let verif_reporter = create_verification_reporter(TmInSharedPoolSenderWithId::new(
ComponentIdList::PusVerification as ComponentId, let (mgm_handler_composite_tx, mgm_handler_composite_rx) =
"verif_sender", mpsc::channel::<GenericMessage<CompositeRequest>>();
shared_tm_pool.clone(), let (mgm_handler_mode_tx, mgm_handler_mode_rx) = mpsc::channel::<GenericMessage<ModeRequest>>();
tm_funnel_tx.clone(),
));
let acs_target_id = TargetAndApidId::new(PUS_APID, RequestTargetId::AcsSubsystem as u32);
let (acs_thread_tx, acs_thread_rx) = channel::<GenericMessage<CompositeRequest>>();
// Some request are targetable. This map is used to retrieve sender handles based on a target ID. // Some request are targetable. This map is used to retrieve sender handles based on a target ID.
let mut request_map = GenericRequestRouter::default(); let mut request_map = GenericRequestRouter::default();
request_map.0.insert(acs_target_id.into(), acs_thread_tx); request_map
.composite_router_map
.insert(MGM_HANDLER_0.id(), mgm_handler_composite_tx);
request_map
.mode_router_map
.insert(MGM_HANDLER_0.id(), mgm_handler_mode_tx);
// This helper structure is used by all telecommand providers which need to send telecommands // This helper structure is used by all telecommand providers which need to send telecommands
// to the TC source. // to the TC source.
@ -105,88 +96,80 @@ fn static_tmtc_pool_main() {
// The event task is the core handler to perform the event routing and TM handling as specified // The event task is the core handler to perform the event routing and TM handling as specified
// in the sat-rs documentation. // in the sat-rs documentation.
let mut event_handler = EventHandler::new( let mut event_handler = EventHandler::new(tm_funnel_tx.clone(), event_request_rx);
TmInSharedPoolSenderWithId::new(
ComponentIdList::EventManagement as ComponentId,
"ALL_EVENTS_TX",
shared_tm_pool.clone(),
tm_funnel_tx.clone(),
),
verif_reporter.clone(),
event_request_rx,
);
let (pus_test_tx, pus_test_rx) = channel(); let (pus_test_tx, pus_test_rx) = mpsc::channel();
let (pus_event_tx, pus_event_rx) = channel(); let (pus_event_tx, pus_event_rx) = mpsc::channel();
let (pus_sched_tx, pus_sched_rx) = channel(); let (pus_sched_tx, pus_sched_rx) = mpsc::channel();
let (pus_hk_tx, pus_hk_rx) = channel(); let (pus_hk_tx, pus_hk_rx) = mpsc::channel();
let (pus_action_tx, pus_action_rx) = channel(); let (pus_action_tx, pus_action_rx) = mpsc::channel();
let (pus_mode_tx, pus_mode_rx) = mpsc::channel();
let (pus_action_reply_tx, pus_action_reply_rx) = channel(); let (_pus_action_reply_tx, pus_action_reply_rx) = mpsc::channel();
let (pus_hk_reply_tx, pus_hk_reply_rx) = channel(); let (pus_hk_reply_tx, pus_hk_reply_rx) = mpsc::channel();
let (pus_mode_reply_tx, pus_mode_reply_rx) = mpsc::channel();
let pus_router = PusTcMpscRouter { let pus_router = PusTcMpscRouter {
test_service_receiver: pus_test_tx, test_tc_sender: pus_test_tx,
event_service_receiver: pus_event_tx, event_tc_sender: pus_event_tx,
sched_service_receiver: pus_sched_tx, sched_tc_sender: pus_sched_tx,
hk_service_receiver: pus_hk_tx, hk_tc_sender: pus_hk_tx,
action_service_receiver: pus_action_tx, action_tc_sender: pus_action_tx,
mode_tc_sender: pus_mode_tx,
}; };
let pus_test_service = create_test_service_static( let pus_test_service = create_test_service_static(
shared_tm_pool.clone(), tm_funnel_tx_sender.clone(),
tm_funnel_tx.clone(),
verif_reporter.clone(),
shared_tc_pool.pool.clone(), shared_tc_pool.pool.clone(),
event_handler.clone_event_sender(), event_handler.clone_event_sender(),
pus_test_rx, pus_test_rx,
); );
let pus_scheduler_service = create_scheduler_service_static( let pus_scheduler_service = create_scheduler_service_static(
shared_tm_pool.clone(), tm_funnel_tx_sender.clone(),
tm_funnel_tx.clone(),
verif_reporter.clone(),
tc_source.clone(), tc_source.clone(),
pus_sched_rx, pus_sched_rx,
create_sched_tc_pool(), create_sched_tc_pool(),
); );
let pus_event_service = create_event_service_static( let pus_event_service = create_event_service_static(
shared_tm_pool.clone(), tm_funnel_tx_sender.clone(),
tm_funnel_tx.clone(),
verif_reporter.clone(),
shared_tc_pool.pool.clone(), shared_tc_pool.pool.clone(),
pus_event_rx, pus_event_rx,
event_request_tx, event_request_tx,
); );
let pus_action_service = create_action_service_static( let pus_action_service = create_action_service_static(
shared_tm_pool.clone(), tm_funnel_tx_sender.clone(),
tm_funnel_tx.clone(),
verif_reporter.clone(),
shared_tc_pool.pool.clone(), shared_tc_pool.pool.clone(),
pus_action_rx, pus_action_rx,
request_map.clone(), request_map.clone(),
pus_action_reply_rx, pus_action_reply_rx,
); );
let pus_hk_service = create_hk_service_static( let pus_hk_service = create_hk_service_static(
shared_tm_pool.clone(), tm_funnel_tx_sender.clone(),
tm_funnel_tx.clone(),
verif_reporter.clone(),
shared_tc_pool.pool.clone(), shared_tc_pool.pool.clone(),
pus_hk_rx, pus_hk_rx,
request_map, request_map.clone(),
pus_hk_reply_rx, pus_hk_reply_rx,
); );
let pus_mode_service = create_mode_service_static(
tm_funnel_tx_sender.clone(),
shared_tc_pool.pool.clone(),
pus_mode_rx,
request_map,
pus_mode_reply_rx,
);
let mut pus_stack = PusStack::new( let mut pus_stack = PusStack::new(
pus_test_service,
pus_hk_service, pus_hk_service,
pus_event_service, pus_event_service,
pus_action_service, pus_action_service,
pus_scheduler_service, pus_scheduler_service,
pus_test_service, pus_mode_service,
); );
let ccsds_receiver = CcsdsReceiver { tc_source }; let ccsds_receiver = CcsdsReceiver { tc_source };
let mut tmtc_task = TcSourceTaskStatic::new( let mut tmtc_task = TcSourceTaskStatic::new(
shared_tc_pool.clone(), shared_tc_pool.clone(),
tc_source_rx, tc_source_rx,
PusReceiver::new(verif_reporter.clone(), pus_router), PusReceiver::new(tm_funnel_tx_sender, pus_router),
); );
let sock_addr = SocketAddr::new(IpAddr::V4(OBSW_SERVER_ADDR), SERVER_PORT); let sock_addr = SocketAddr::new(IpAddr::V4(OBSW_SERVER_ADDR), SERVER_PORT);
@ -211,19 +194,6 @@ fn static_tmtc_pool_main() {
) )
.expect("tcp server creation failed"); .expect("tcp server creation failed");
/*
let mut acs_task = AcsTask::new(
TmInSharedPoolSenderWithId::new(
TmSenderId::AcsSubsystem as ChannelId,
"ACS_TASK_SENDER",
shared_tm_pool.clone(),
tm_funnel_tx.clone(),
),
acs_thread_rx,
verif_reporter,
);
*/
let mut tm_funnel = TmFunnelStatic::new( let mut tm_funnel = TmFunnelStatic::new(
shared_tm_pool, shared_tm_pool,
sync_tm_tcp_source, sync_tm_tcp_source,
@ -231,6 +201,24 @@ fn static_tmtc_pool_main() {
tm_server_tx, tm_server_tx,
); );
let (mgm_handler_mode_reply_to_parent_tx, _mgm_handler_mode_reply_to_parent_rx) =
mpsc::channel();
let dummy_spi_interface = SpiDummyInterface::default();
let shared_mgm_set = Arc::default();
let mut mgm_handler = MgmHandler::new(
MGM_HANDLER_0,
"MGM_0",
mgm_handler_mode_rx,
mgm_handler_composite_rx,
pus_mode_reply_tx,
mgm_handler_mode_reply_to_parent_tx,
pus_hk_reply_tx,
tm_funnel_tx,
dummy_spi_interface,
shared_mgm_set,
);
info!("Starting TMTC and UDP task"); info!("Starting TMTC and UDP task");
let jh_udp_tmtc = thread::Builder::new() let jh_udp_tmtc = thread::Builder::new()
.name("TMTC and UDP".to_string()) .name("TMTC and UDP".to_string())
@ -276,7 +264,7 @@ fn static_tmtc_pool_main() {
let jh_aocs = thread::Builder::new() let jh_aocs = thread::Builder::new()
.name("AOCS".to_string()) .name("AOCS".to_string())
.spawn(move || loop { .spawn(move || loop {
// acs_task.periodic_operation(); mgm_handler.periodic_operation();
thread::sleep(Duration::from_millis(FREQ_MS_AOCS)); thread::sleep(Duration::from_millis(FREQ_MS_AOCS));
}) })
.unwrap(); .unwrap();
@ -310,22 +298,23 @@ fn static_tmtc_pool_main() {
#[allow(dead_code)] #[allow(dead_code)]
fn dyn_tmtc_pool_main() { fn dyn_tmtc_pool_main() {
let (tc_source_tx, tc_source_rx) = channel(); let (tc_source_tx, tc_source_rx) = mpsc::channel();
let (tm_funnel_tx, tm_funnel_rx) = channel(); let (tm_funnel_tx, tm_funnel_rx) = mpsc::channel();
let (tm_server_tx, tm_server_rx) = channel(); let (tm_server_tx, tm_server_rx) = mpsc::channel();
// Every software component which needs to generate verification telemetry, gets a cloned
// verification reporter. // Some request are targetable. This map is used to retrieve sender handles based on a target ID.
let verif_reporter = create_verification_reporter(TmAsVecSenderWithId::new( let (mgm_handler_composite_tx, mgm_handler_composite_rx) =
ComponentIdList::PusVerification as ComponentId, mpsc::channel::<GenericMessage<CompositeRequest>>();
"verif_sender", let (mgm_handler_mode_tx, mgm_handler_mode_rx) = mpsc::channel::<GenericMessage<ModeRequest>>();
tm_funnel_tx.clone(),
));
let acs_target_id = TargetAndApidId::new(PUS_APID, RequestTargetId::AcsSubsystem as u32);
let (acs_thread_tx, acs_thread_rx) = channel::<GenericMessage<CompositeRequest>>();
// Some request are targetable. This map is used to retrieve sender handles based on a target ID. // Some request are targetable. This map is used to retrieve sender handles based on a target ID.
let mut request_map = GenericRequestRouter::default(); let mut request_map = GenericRequestRouter::default();
request_map.0.insert(acs_target_id.into(), acs_thread_tx); request_map
.composite_router_map
.insert(MGM_HANDLER_0.raw(), mgm_handler_composite_tx);
request_map
.mode_router_map
.insert(MGM_HANDLER_0.raw(), mgm_handler_mode_tx);
let tc_source = PusTcSourceProviderDynamic(tc_source_tx); let tc_source = PusTcSourceProviderDynamic(tc_source_tx);
@ -335,80 +324,74 @@ fn dyn_tmtc_pool_main() {
let (event_request_tx, event_request_rx) = mpsc::channel::<EventRequestWithToken>(); let (event_request_tx, event_request_rx) = mpsc::channel::<EventRequestWithToken>();
// The event task is the core handler to perform the event routing and TM handling as specified // The event task is the core handler to perform the event routing and TM handling as specified
// in the sat-rs documentation. // in the sat-rs documentation.
let mut event_handler = EventHandler::new( let mut event_handler = EventHandler::new(tm_funnel_tx.clone(), event_request_rx);
TmAsVecSenderWithId::new(
ComponentIdList::EventManagement as ComponentId,
"ALL_EVENTS_TX",
tm_funnel_tx.clone(),
),
verif_reporter.clone(),
event_request_rx,
);
let (pus_test_tx, pus_test_rx) = channel(); let (pus_test_tx, pus_test_rx) = mpsc::channel();
let (pus_event_tx, pus_event_rx) = channel(); let (pus_event_tx, pus_event_rx) = mpsc::channel();
let (pus_sched_tx, pus_sched_rx) = channel(); let (pus_sched_tx, pus_sched_rx) = mpsc::channel();
let (pus_hk_tx, pus_hk_rx) = channel(); let (pus_hk_tx, pus_hk_rx) = mpsc::channel();
let (pus_action_tx, pus_action_rx) = channel(); let (pus_action_tx, pus_action_rx) = mpsc::channel();
let (pus_mode_tx, pus_mode_rx) = mpsc::channel();
let (pus_action_reply_tx, pus_action_reply_rx) = channel(); let (_pus_action_reply_tx, pus_action_reply_rx) = mpsc::channel();
let (pus_hk_reply_tx, pus_hk_reply_rx) = channel(); let (pus_hk_reply_tx, pus_hk_reply_rx) = mpsc::channel();
let (pus_mode_reply_tx, pus_mode_reply_rx) = mpsc::channel();
let pus_router = PusTcMpscRouter { let pus_router = PusTcMpscRouter {
test_service_receiver: pus_test_tx, test_tc_sender: pus_test_tx,
event_service_receiver: pus_event_tx, event_tc_sender: pus_event_tx,
sched_service_receiver: pus_sched_tx, sched_tc_sender: pus_sched_tx,
hk_service_receiver: pus_hk_tx, hk_tc_sender: pus_hk_tx,
action_service_receiver: pus_action_tx, action_tc_sender: pus_action_tx,
mode_tc_sender: pus_mode_tx,
}; };
let pus_test_service = create_test_service_dynamic( let pus_test_service = create_test_service_dynamic(
tm_funnel_tx.clone(), tm_funnel_tx.clone(),
verif_reporter.clone(),
event_handler.clone_event_sender(), event_handler.clone_event_sender(),
pus_test_rx, pus_test_rx,
); );
let pus_scheduler_service = create_scheduler_service_dynamic( let pus_scheduler_service = create_scheduler_service_dynamic(
tm_funnel_tx.clone(), tm_funnel_tx.clone(),
verif_reporter.clone(),
tc_source.0.clone(), tc_source.0.clone(),
pus_sched_rx, pus_sched_rx,
create_sched_tc_pool(), create_sched_tc_pool(),
); );
let pus_event_service = create_event_service_dynamic( let pus_event_service =
tm_funnel_tx.clone(), create_event_service_dynamic(tm_funnel_tx.clone(), pus_event_rx, event_request_tx);
verif_reporter.clone(),
pus_event_rx,
event_request_tx,
);
let pus_action_service = create_action_service_dynamic( let pus_action_service = create_action_service_dynamic(
tm_funnel_tx.clone(), tm_funnel_tx.clone(),
verif_reporter.clone(),
pus_action_rx, pus_action_rx,
request_map.clone(), request_map.clone(),
pus_action_reply_rx, pus_action_reply_rx,
); );
let pus_hk_service = create_hk_service_dynamic( let pus_hk_service = create_hk_service_dynamic(
tm_funnel_tx.clone(), tm_funnel_tx.clone(),
verif_reporter.clone(),
pus_hk_rx, pus_hk_rx,
request_map, request_map.clone(),
pus_hk_reply_rx, pus_hk_reply_rx,
); );
let pus_mode_service = create_mode_service_dynamic(
tm_funnel_tx.clone(),
pus_mode_rx,
request_map,
pus_mode_reply_rx,
);
let mut pus_stack = PusStack::new( let mut pus_stack = PusStack::new(
pus_test_service,
pus_hk_service, pus_hk_service,
pus_event_service, pus_event_service,
pus_action_service, pus_action_service,
pus_scheduler_service, pus_scheduler_service,
pus_test_service, pus_mode_service,
); );
let ccsds_receiver = CcsdsReceiver { tc_source }; let ccsds_receiver = CcsdsReceiver { tc_source };
let mut tmtc_task = TcSourceTaskDynamic::new( let mut tmtc_task = TcSourceTaskDynamic::new(
tc_source_rx, tc_source_rx,
PusReceiver::new(verif_reporter.clone(), pus_router), PusReceiver::new(tm_funnel_tx.clone(), pus_router),
); );
let sock_addr = SocketAddr::new(IpAddr::V4(OBSW_SERVER_ADDR), SERVER_PORT); let sock_addr = SocketAddr::new(IpAddr::V4(OBSW_SERVER_ADDR), SERVER_PORT);
@ -432,19 +415,25 @@ fn dyn_tmtc_pool_main() {
) )
.expect("tcp server creation failed"); .expect("tcp server creation failed");
/*
let mut acs_task = AcsTask::new(
TmAsVecSenderWithId::new(
TmSenderId::AcsSubsystem as ComponentId,
"ACS_TASK_SENDER",
tm_funnel_tx.clone(),
),
acs_thread_rx,
verif_reporter,
);
*/
let mut tm_funnel = TmFunnelDynamic::new(sync_tm_tcp_source, tm_funnel_rx, tm_server_tx); let mut tm_funnel = TmFunnelDynamic::new(sync_tm_tcp_source, tm_funnel_rx, tm_server_tx);
let (mgm_handler_mode_reply_to_parent_tx, _mgm_handler_mode_reply_to_parent_rx) =
mpsc::channel();
let dummy_spi_interface = SpiDummyInterface::default();
let shared_mgm_set = Arc::default();
let mut mgm_handler = MgmHandler::new(
MGM_HANDLER_0,
"MGM_0",
mgm_handler_mode_rx,
mgm_handler_composite_rx,
pus_mode_reply_tx,
mgm_handler_mode_reply_to_parent_tx,
pus_hk_reply_tx,
tm_funnel_tx,
dummy_spi_interface,
shared_mgm_set,
);
info!("Starting TMTC and UDP task"); info!("Starting TMTC and UDP task");
let jh_udp_tmtc = thread::Builder::new() let jh_udp_tmtc = thread::Builder::new()
.name("TMTC and UDP".to_string()) .name("TMTC and UDP".to_string())
@ -490,7 +479,7 @@ fn dyn_tmtc_pool_main() {
let jh_aocs = thread::Builder::new() let jh_aocs = thread::Builder::new()
.name("AOCS".to_string()) .name("AOCS".to_string())
.spawn(move || loop { .spawn(move || loop {
// acs_task.periodic_operation(); mgm_handler.periodic_operation();
thread::sleep(Duration::from_millis(FREQ_MS_AOCS)); thread::sleep(Duration::from_millis(FREQ_MS_AOCS));
}) })
.unwrap(); .unwrap();
@ -531,7 +520,7 @@ fn main() {
dyn_tmtc_pool_main(); dyn_tmtc_pool_main();
} }
pub fn update_time(time_provider: &mut TimeProvider, timestamp: &mut [u8]) { pub fn update_time(time_provider: &mut CdsTime, timestamp: &mut [u8]) {
time_provider time_provider
.update_from_now() .update_from_now()
.expect("Could not get current time"); .expect("Could not get current time");

View File

@ -1,34 +1,35 @@
use log::{error, warn}; use log::{error, warn};
use satrs::action::{ActionRequest, ActionRequestVariant}; use satrs::action::{ActionRequest, ActionRequestVariant};
use satrs::params::WritableToBeBytes; use satrs::params::WritableToBeBytes;
use satrs::pool::{SharedStaticMemoryPool, StoreAddr}; use satrs::pool::SharedStaticMemoryPool;
use satrs::pus::action::{ use satrs::pus::action::{
ActionReplyVariant, ActivePusActionRequestStd, DefaultActiveActionRequestMap, PusActionReply, ActionReplyVariant, ActivePusActionRequestStd, DefaultActiveActionRequestMap, PusActionReply,
}; };
use satrs::pus::verification::{ use satrs::pus::verification::{
FailParams, FailParamsWithStep, TcStateAccepted, TcStateStarted, FailParams, FailParamsWithStep, TcStateAccepted, TcStateStarted, VerificationReporter,
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender,
VerificationReportingProvider, VerificationToken, VerificationReportingProvider, VerificationToken,
}; };
use satrs::pus::{ use satrs::pus::{
ActiveRequestProvider, EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, ActiveRequestProvider, EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter,
EcssTcInVecConverter, EcssTcReceiverCore, EcssTmSenderCore, EcssTmtcError, EcssTcInVecConverter, EcssTmSenderCore, EcssTmtcError, GenericConversionError, MpscTcReceiver,
GenericConversionError, MpscTcReceiver, PusPacketHandlerResult, PusReplyHandler, MpscTmAsVecSender, MpscTmInSharedPoolSenderBounded, PusPacketHandlerResult, PusReplyHandler,
PusServiceHelper, PusTcToRequestConverter, TmAsVecSenderWithId, TmAsVecSenderWithMpsc, PusServiceHelper, PusTcToRequestConverter, PusTmAsVec, PusTmInPool, TmInSharedPoolSender,
TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithId,
}; };
use satrs::request::{GenericMessage, TargetAndApidId}; use satrs::request::{GenericMessage, UniqueApidTargetId};
use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::{EcssEnumU16, PusPacket}; use satrs::spacepackets::ecss::{EcssEnumU16, PusPacket};
use satrs::tmtc::tm_helper::SharedTmPool;
use satrs::ComponentId; use satrs::ComponentId;
use satrs_example::config::{tmtc_err, ComponentIdList, PUS_APID}; use satrs_example::config::components::PUS_ACTION_SERVICE;
use std::sync::mpsc::{self}; use satrs_example::config::tmtc_err;
use std::sync::mpsc;
use std::time::Duration; use std::time::Duration;
use crate::requests::GenericRequestRouter; use crate::requests::GenericRequestRouter;
use super::{generic_pus_request_timeout_handler, PusTargetedRequestService, TargetedPusService}; use super::{
create_verification_reporter, generic_pus_request_timeout_handler, PusTargetedRequestService,
TargetedPusService,
};
pub struct ActionReplyHandler { pub struct ActionReplyHandler {
fail_data_buf: [u8; 128], fail_data_buf: [u8; 128],
@ -47,20 +48,22 @@ impl PusReplyHandler<ActivePusActionRequestStd, PusActionReply> for ActionReplyH
fn handle_unrequested_reply( fn handle_unrequested_reply(
&mut self, &mut self,
_caller_id: ComponentId,
reply: &GenericMessage<PusActionReply>, reply: &GenericMessage<PusActionReply>,
_tm_sender: &impl EcssTmSenderCore, _tm_sender: &impl EcssTmSenderCore,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
log::warn!("received unexpected reply for service 8: {reply:?}"); warn!("received unexpected reply for service 8: {reply:?}");
Ok(()) Ok(())
} }
fn handle_reply( fn handle_reply(
&mut self, &mut self,
reply: &satrs::request::GenericMessage<PusActionReply>, caller_id: ComponentId,
reply: &GenericMessage<PusActionReply>,
active_request: &ActivePusActionRequestStd, active_request: &ActivePusActionRequestStd,
tm_sender: &(impl EcssTmSenderCore + ?Sized),
verification_handler: &impl VerificationReportingProvider, verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8], time_stamp: &[u8],
_tm_sender: &impl EcssTmSenderCore,
) -> Result<bool, Self::Error> { ) -> Result<bool, Self::Error> {
let verif_token: VerificationToken<TcStateStarted> = active_request let verif_token: VerificationToken<TcStateStarted> = active_request
.token() .token()
@ -72,16 +75,12 @@ impl PusReplyHandler<ActivePusActionRequestStd, PusActionReply> for ActionReplyH
if let Some(params) = params { if let Some(params) = params {
fail_data_len = params.write_to_be_bytes(&mut self.fail_data_buf)?; fail_data_len = params.write_to_be_bytes(&mut self.fail_data_buf)?;
} }
verification_handler verification_handler.completion_failure(
.completion_failure( caller_id,
verif_token, tm_sender,
FailParams::new( verif_token,
time_stamp, FailParams::new(time_stamp, error_code, &self.fail_data_buf[..fail_data_len]),
error_code, )?;
&self.fail_data_buf[..fail_data_len],
),
)
.map_err(|e| e.0)?;
true true
} }
ActionReplyVariant::StepFailed { ActionReplyVariant::StepFailed {
@ -93,27 +92,32 @@ impl PusReplyHandler<ActivePusActionRequestStd, PusActionReply> for ActionReplyH
if let Some(params) = params { if let Some(params) = params {
fail_data_len = params.write_to_be_bytes(&mut self.fail_data_buf)?; fail_data_len = params.write_to_be_bytes(&mut self.fail_data_buf)?;
} }
verification_handler verification_handler.step_failure(
.step_failure( caller_id,
verif_token, tm_sender,
FailParamsWithStep::new( verif_token,
time_stamp, FailParamsWithStep::new(
&EcssEnumU16::new(*step), time_stamp,
error_code, &EcssEnumU16::new(*step),
&self.fail_data_buf[..fail_data_len], error_code,
), &self.fail_data_buf[..fail_data_len],
) ),
.map_err(|e| e.0)?; )?;
true true
} }
ActionReplyVariant::Completed => { ActionReplyVariant::Completed => {
verification_handler verification_handler.completion_success(
.completion_success(verif_token, time_stamp) caller_id,
.map_err(|e| e.0)?; tm_sender,
verif_token,
time_stamp,
)?;
true true
} }
ActionReplyVariant::StepSuccess { step } => { ActionReplyVariant::StepSuccess { step } => {
verification_handler.step_success( verification_handler.step_success(
caller_id,
tm_sender,
&verif_token, &verif_token,
time_stamp, time_stamp,
EcssEnumU16::new(*step), EcssEnumU16::new(*step),
@ -127,12 +131,15 @@ impl PusReplyHandler<ActivePusActionRequestStd, PusActionReply> for ActionReplyH
fn handle_request_timeout( fn handle_request_timeout(
&mut self, &mut self,
caller_id: ComponentId,
active_request: &ActivePusActionRequestStd, active_request: &ActivePusActionRequestStd,
tm_sender: &impl EcssTmSenderCore,
verification_handler: &impl VerificationReportingProvider, verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8], time_stamp: &[u8],
_tm_sender: &impl EcssTmSenderCore,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
generic_pus_request_timeout_handler( generic_pus_request_timeout_handler(
caller_id,
tm_sender,
active_request, active_request,
verification_handler, verification_handler,
time_stamp, time_stamp,
@ -149,16 +156,20 @@ impl PusTcToRequestConverter<ActivePusActionRequestStd, ActionRequest> for Actio
fn convert( fn convert(
&mut self, &mut self,
caller_id: ComponentId,
token: VerificationToken<TcStateAccepted>, token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader, tc: &PusTcReader,
time_stamp: &[u8], tm_sender: &(impl EcssTmSenderCore + ?Sized),
verif_reporter: &impl VerificationReportingProvider, verif_reporter: &impl VerificationReportingProvider,
time_stamp: &[u8],
) -> Result<(ActivePusActionRequestStd, ActionRequest), Self::Error> { ) -> Result<(ActivePusActionRequestStd, ActionRequest), Self::Error> {
let subservice = tc.subservice(); let subservice = tc.subservice();
let user_data = tc.user_data(); let user_data = tc.user_data();
if user_data.len() < 8 { if user_data.len() < 8 {
verif_reporter verif_reporter
.start_failure( .start_failure(
caller_id,
tm_sender,
token, token,
FailParams::new_no_fail_data(time_stamp, &tmtc_err::NOT_ENOUGH_APP_DATA), FailParams::new_no_fail_data(time_stamp, &tmtc_err::NOT_ENOUGH_APP_DATA),
) )
@ -168,7 +179,7 @@ impl PusTcToRequestConverter<ActivePusActionRequestStd, ActionRequest> for Actio
found: user_data.len(), found: user_data.len(),
}); });
} }
let target_id_and_apid = TargetAndApidId::from_pus_tc(tc).unwrap(); let target_id_and_apid = UniqueApidTargetId::from_pus_tc(tc).unwrap();
let action_id = u32::from_be_bytes(user_data[4..8].try_into().unwrap()); let action_id = u32::from_be_bytes(user_data[4..8].try_into().unwrap());
if subservice == 128 { if subservice == 128 {
let req_variant = if user_data.len() == 8 { let req_variant = if user_data.len() == 8 {
@ -188,6 +199,8 @@ impl PusTcToRequestConverter<ActivePusActionRequestStd, ActionRequest> for Actio
} else { } else {
verif_reporter verif_reporter
.start_failure( .start_failure(
caller_id,
tm_sender,
token, token,
FailParams::new_no_fail_data(time_stamp, &tmtc_err::INVALID_PUS_SUBSERVICE), FailParams::new_no_fail_data(time_stamp, &tmtc_err::INVALID_PUS_SUBSERVICE),
) )
@ -198,37 +211,18 @@ impl PusTcToRequestConverter<ActivePusActionRequestStd, ActionRequest> for Actio
} }
pub fn create_action_service_static( pub fn create_action_service_static(
shared_tm_store: SharedTmPool, tm_sender: TmInSharedPoolSender<mpsc::SyncSender<PusTmInPool>>,
tm_funnel_tx: mpsc::SyncSender<StoreAddr>,
verif_reporter: VerificationReporterWithSharedPoolMpscBoundedSender,
tc_pool: SharedStaticMemoryPool, tc_pool: SharedStaticMemoryPool,
pus_action_rx: mpsc::Receiver<EcssTcAndToken>, pus_action_rx: mpsc::Receiver<EcssTcAndToken>,
action_router: GenericRequestRouter, action_router: GenericRequestRouter,
reply_receiver: mpsc::Receiver<GenericMessage<PusActionReply>>, reply_receiver: mpsc::Receiver<GenericMessage<PusActionReply>>,
) -> Pus8Wrapper< ) -> ActionServiceWrapper<MpscTmInSharedPoolSenderBounded, EcssTcInSharedStoreConverter> {
MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc,
EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender,
> {
let action_srv_tm_sender = TmInSharedPoolSenderWithId::new(
ComponentIdList::PusAction as ComponentId,
"PUS_8_TM_SENDER",
shared_tm_store.clone(),
tm_funnel_tx.clone(),
);
let action_srv_receiver = MpscTcReceiver::new(
ComponentIdList::PusAction as ComponentId,
"PUS_8_TC_RECV",
pus_action_rx,
);
let action_request_handler = PusTargetedRequestService::new( let action_request_handler = PusTargetedRequestService::new(
ComponentIdList::PusAction as ComponentId,
PusServiceHelper::new( PusServiceHelper::new(
action_srv_receiver, PUS_ACTION_SERVICE.raw(),
action_srv_tm_sender.clone(), pus_action_rx,
PUS_APID, tm_sender,
verif_reporter.clone(), create_verification_reporter(PUS_ACTION_SERVICE.apid),
EcssTcInSharedStoreConverter::new(tc_pool.clone(), 2048), EcssTcInSharedStoreConverter::new(tc_pool.clone(), 2048),
), ),
ActionRequestConverter::default(), ActionRequestConverter::default(),
@ -239,40 +233,23 @@ pub fn create_action_service_static(
action_router, action_router,
reply_receiver, reply_receiver,
); );
Pus8Wrapper { ActionServiceWrapper {
service: action_request_handler, service: action_request_handler,
} }
} }
pub fn create_action_service_dynamic( pub fn create_action_service_dynamic(
tm_funnel_tx: mpsc::Sender<Vec<u8>>, tm_funnel_tx: mpsc::Sender<PusTmAsVec>,
verif_reporter: VerificationReporterWithVecMpscSender,
pus_action_rx: mpsc::Receiver<EcssTcAndToken>, pus_action_rx: mpsc::Receiver<EcssTcAndToken>,
action_router: GenericRequestRouter, action_router: GenericRequestRouter,
reply_receiver: mpsc::Receiver<GenericMessage<PusActionReply>>, reply_receiver: mpsc::Receiver<GenericMessage<PusActionReply>>,
) -> Pus8Wrapper< ) -> ActionServiceWrapper<MpscTmAsVecSender, EcssTcInVecConverter> {
MpscTcReceiver,
TmAsVecSenderWithMpsc,
EcssTcInVecConverter,
VerificationReporterWithVecMpscSender,
> {
let action_srv_tm_sender = TmAsVecSenderWithId::new(
ComponentIdList::PusAction as ComponentId,
"PUS_8_TM_SENDER",
tm_funnel_tx.clone(),
);
let action_srv_receiver = MpscTcReceiver::new(
ComponentIdList::PusAction as ComponentId,
"PUS_8_TC_RECV",
pus_action_rx,
);
let action_request_handler = PusTargetedRequestService::new( let action_request_handler = PusTargetedRequestService::new(
ComponentIdList::PusAction as ComponentId,
PusServiceHelper::new( PusServiceHelper::new(
action_srv_receiver, PUS_ACTION_SERVICE.raw(),
action_srv_tm_sender.clone(), pus_action_rx,
PUS_APID, tm_funnel_tx,
verif_reporter.clone(), create_verification_reporter(PUS_ACTION_SERVICE.apid),
EcssTcInVecConverter::default(), EcssTcInVecConverter::default(),
), ),
ActionRequestConverter::default(), ActionRequestConverter::default(),
@ -281,19 +258,15 @@ pub fn create_action_service_dynamic(
action_router, action_router,
reply_receiver, reply_receiver,
); );
Pus8Wrapper { ActionServiceWrapper {
service: action_request_handler, service: action_request_handler,
} }
} }
pub struct Pus8Wrapper< pub struct ActionServiceWrapper<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter>
TcReceiver: EcssTcReceiverCore, {
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> {
pub(crate) service: PusTargetedRequestService< pub(crate) service: PusTargetedRequestService<
TcReceiver, MpscTcReceiver,
TmSender, TmSender,
TcInMemConverter, TcInMemConverter,
VerificationReporter, VerificationReporter,
@ -306,13 +279,8 @@ pub struct Pus8Wrapper<
>, >,
} }
impl< impl<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter> TargetedPusService
TcReceiver: EcssTcReceiverCore, for ActionServiceWrapper<TmSender, TcInMemConverter>
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> TargetedPusService
for Pus8Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{ {
/// Returns [true] if the packet handling is finished. /// Returns [true] if the packet handling is finished.
fn poll_and_handle_next_tc(&mut self, time_stamp: &[u8]) -> bool { fn poll_and_handle_next_tc(&mut self, time_stamp: &[u8]) -> bool {
@ -340,13 +308,12 @@ impl<
} }
fn poll_and_handle_next_reply(&mut self, time_stamp: &[u8]) -> bool { fn poll_and_handle_next_reply(&mut self, time_stamp: &[u8]) -> bool {
match self.service.poll_and_check_next_reply(time_stamp) { self.service
Ok(packet_handled) => packet_handled, .poll_and_check_next_reply(time_stamp)
Err(e) => { .unwrap_or_else(|e| {
log::warn!("PUS 8: Handling reply failed with error {e:?}"); warn!("PUS 8: Handling reply failed with error {e:?}");
false false
} })
}
} }
fn check_for_request_timeouts(&mut self) { fn check_for_request_timeouts(&mut self) {
@ -356,8 +323,10 @@ impl<
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use satrs::pus::test_util::{TEST_APID, TEST_COMPONENT_ID, TEST_UNIQUE_ID};
use satrs::pus::verification::test_util::TestVerificationReporter;
use satrs::request::MessageMetadata;
use satrs::{ use satrs::{
pus::verification::VerificationReporterCfg,
res_code::ResultU16, res_code::ResultU16,
spacepackets::{ spacepackets::{
ecss::{ ecss::{
@ -370,10 +339,7 @@ mod tests {
}; };
use crate::{ use crate::{
pus::tests::{ pus::tests::{PusConverterTestbench, ReplyHandlerTestbench, TargetedPusRequestTestbench},
PusConverterTestbench, ReplyHandlerTestbench, TargetedPusRequestTestbench, TARGET_ID,
TEST_APID, TEST_APID_TARGET_ID,
},
requests::CompositeRequest, requests::CompositeRequest,
}; };
@ -391,31 +357,22 @@ mod tests {
{ {
pub fn new_for_action() -> Self { pub fn new_for_action() -> Self {
let _ = env_logger::builder().is_test(true).try_init(); let _ = env_logger::builder().is_test(true).try_init();
let target_and_apid_id = TargetAndApidId::new(TEST_APID, TEST_APID_TARGET_ID);
let (tm_funnel_tx, tm_funnel_rx) = mpsc::channel(); let (tm_funnel_tx, tm_funnel_rx) = mpsc::channel();
let (pus_action_tx, pus_action_rx) = mpsc::channel(); let (pus_action_tx, pus_action_rx) = mpsc::channel();
let (action_reply_tx, action_reply_rx) = mpsc::channel(); let (action_reply_tx, action_reply_rx) = mpsc::channel();
let (action_req_tx, action_req_rx) = mpsc::channel(); let (action_req_tx, action_req_rx) = mpsc::channel();
let verif_reporter_cfg = VerificationReporterCfg::new(TEST_APID, 2, 2, 64).unwrap(); let verif_reporter = TestVerificationReporter::default();
let tm_as_vec_sender =
TmAsVecSenderWithMpsc::new(1, "VERIF_SENDER", tm_funnel_tx.clone());
let verif_reporter =
VerificationReporterWithVecMpscSender::new(&verif_reporter_cfg, tm_as_vec_sender);
let mut generic_req_router = GenericRequestRouter::default(); let mut generic_req_router = GenericRequestRouter::default();
generic_req_router generic_req_router
.0 .composite_router_map
.insert(target_and_apid_id.into(), action_req_tx); .insert(TEST_APID.into(), action_req_tx);
let action_srv_tm_sender =
TmAsVecSenderWithId::new(0, "TESTBENCH", tm_funnel_tx.clone());
let action_srv_receiver = MpscTcReceiver::new(0, "TESTBENCH", pus_action_rx);
Self { Self {
service: PusTargetedRequestService::new( service: PusTargetedRequestService::new(
0,
PusServiceHelper::new( PusServiceHelper::new(
action_srv_receiver, 0,
action_srv_tm_sender.clone(), pus_action_rx,
PUS_APID, tm_funnel_tx.clone(),
verif_reporter.clone(), verif_reporter,
EcssTcInVecConverter::default(), EcssTcInVecConverter::default(),
), ),
ActionRequestConverter::default(), ActionRequestConverter::default(),
@ -424,7 +381,6 @@ mod tests {
generic_req_router, generic_req_router,
action_reply_rx, action_reply_rx,
), ),
verif_reporter,
pus_packet_tx: pus_action_tx, pus_packet_tx: pus_action_tx,
tm_funnel_rx, tm_funnel_rx,
reply_tx: action_reply_tx, reply_tx: action_reply_tx,
@ -434,7 +390,7 @@ mod tests {
pub fn verify_packet_verification(&self, subservice: u8) { pub fn verify_packet_verification(&self, subservice: u8) {
let next_tm = self.tm_funnel_rx.try_recv().unwrap(); let next_tm = self.tm_funnel_rx.try_recv().unwrap();
let verif_tm = PusTmReader::new(&next_tm, 7).unwrap().0; let verif_tm = PusTmReader::new(&next_tm.packet, 7).unwrap().0;
assert_eq!(verif_tm.apid(), TEST_APID); assert_eq!(verif_tm.apid(), TEST_APID);
assert_eq!(verif_tm.service(), 1); assert_eq!(verif_tm.service(), 1);
assert_eq!(verif_tm.subservice(), subservice); assert_eq!(verif_tm.subservice(), subservice);
@ -445,7 +401,7 @@ mod tests {
if let Err(mpsc::TryRecvError::Empty) = packet { if let Err(mpsc::TryRecvError::Empty) = packet {
} else { } else {
let tm = packet.unwrap(); let tm = packet.unwrap();
let unexpected_tm = PusTmReader::new(&tm, 7).unwrap().0; let unexpected_tm = PusTmReader::new(&tm.packet, 7).unwrap().0;
panic!("unexpected TM packet {unexpected_tm:?}"); panic!("unexpected TM packet {unexpected_tm:?}");
} }
} }
@ -483,19 +439,26 @@ mod tests {
} }
pub fn add_tc(&mut self, tc: &PusTcCreator) { pub fn add_tc(&mut self, tc: &PusTcCreator) {
let token = self.verif_reporter.add_tc(tc); let token = self.service.service_helper.verif_reporter_mut().add_tc(tc);
let accepted_token = self let accepted_token = self
.verif_reporter .service
.acceptance_success(token, &[0; 7]) .service_helper
.verif_reporter()
.acceptance_success(
self.service.service_helper.id(),
self.service.service_helper.tm_sender(),
token,
&[0; 7],
)
.expect("TC acceptance failed"); .expect("TC acceptance failed");
let next_tm = self.tm_funnel_rx.try_recv().unwrap(); let next_tm = self.tm_funnel_rx.try_recv().unwrap();
let verif_tm = PusTmReader::new(&next_tm, 7).unwrap().0; let verif_tm = PusTmReader::new(&next_tm.packet, 7).unwrap().0;
assert_eq!(verif_tm.apid(), TEST_APID); assert_eq!(verif_tm.apid(), TEST_APID);
assert_eq!(verif_tm.service(), 1); assert_eq!(verif_tm.service(), 1);
assert_eq!(verif_tm.subservice(), 1); assert_eq!(verif_tm.subservice(), 1);
if let Err(mpsc::TryRecvError::Empty) = self.tm_funnel_rx.try_recv() { if let Err(mpsc::TryRecvError::Empty) = self.tm_funnel_rx.try_recv() {
} else { } else {
let unexpected_tm = PusTmReader::new(&next_tm, 7).unwrap().0; let unexpected_tm = PusTmReader::new(&next_tm.packet, 7).unwrap().0;
panic!("unexpected TM packet {unexpected_tm:?}"); panic!("unexpected TM packet {unexpected_tm:?}");
} }
self.pus_packet_tx self.pus_packet_tx
@ -512,7 +475,7 @@ mod tests {
let sec_header = PusTcSecondaryHeader::new_simple(8, 128); let sec_header = PusTcSecondaryHeader::new_simple(8, 128);
let action_id = 5_u32; let action_id = 5_u32;
let mut app_data: [u8; 8] = [0; 8]; let mut app_data: [u8; 8] = [0; 8];
app_data[0..4].copy_from_slice(&TEST_APID_TARGET_ID.to_be_bytes()); app_data[0..4].copy_from_slice(&TEST_UNIQUE_ID.to_be_bytes());
app_data[4..8].copy_from_slice(&action_id.to_be_bytes()); app_data[4..8].copy_from_slice(&action_id.to_be_bytes());
let pus8_packet = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true); let pus8_packet = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true);
testbench.add_tc(&pus8_packet); testbench.add_tc(&pus8_packet);
@ -531,11 +494,7 @@ mod tests {
let action_reply = PusActionReply::new(action_id, ActionReplyVariant::Completed); let action_reply = PusActionReply::new(action_id, ActionReplyVariant::Completed);
testbench testbench
.reply_tx .reply_tx
.send(GenericMessage::new( .send(GenericMessage::new(req.requestor_info, action_reply))
req.request_id,
TARGET_ID.into(),
action_reply,
))
.unwrap(); .unwrap();
} else { } else {
panic!("unexpected request type"); panic!("unexpected request type");
@ -556,7 +515,7 @@ mod tests {
let action_id = 5_u32; let action_id = 5_u32;
let mut app_data: [u8; 8] = [0; 8]; let mut app_data: [u8; 8] = [0; 8];
// Invalid ID, routing should fail. // Invalid ID, routing should fail.
app_data[0..4].copy_from_slice(&(TEST_APID_TARGET_ID + 1).to_be_bytes()); app_data[0..4].copy_from_slice(&(TEST_UNIQUE_ID + 1).to_be_bytes());
app_data[4..8].copy_from_slice(&action_id.to_be_bytes()); app_data[4..8].copy_from_slice(&action_id.to_be_bytes());
let pus8_packet = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true); let pus8_packet = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true);
testbench.add_tc(&pus8_packet); testbench.add_tc(&pus8_packet);
@ -575,11 +534,11 @@ mod tests {
let action_id = 5_u32; let action_id = 5_u32;
let mut app_data: [u8; 8] = [0; 8]; let mut app_data: [u8; 8] = [0; 8];
// Invalid ID, routing should fail. // Invalid ID, routing should fail.
app_data[0..4].copy_from_slice(&TEST_APID_TARGET_ID.to_be_bytes()); app_data[0..4].copy_from_slice(&TEST_UNIQUE_ID.to_be_bytes());
app_data[4..8].copy_from_slice(&action_id.to_be_bytes()); app_data[4..8].copy_from_slice(&action_id.to_be_bytes());
let pus8_packet = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true); let pus8_packet = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true);
let token = testbench.add_tc(&pus8_packet); let token = testbench.add_tc(&pus8_packet);
let result = testbench.convert(token, &[], TEST_APID, TEST_APID_TARGET_ID); let result = testbench.convert(token, &[], TEST_APID, TEST_UNIQUE_ID);
assert!(result.is_ok()); assert!(result.is_ok());
let (active_req, request) = result.unwrap(); let (active_req, request) = result.unwrap();
if let ActionRequestVariant::NoData = request.variant { if let ActionRequestVariant::NoData = request.variant {
@ -587,7 +546,7 @@ mod tests {
assert_eq!(active_req.action_id, action_id); assert_eq!(active_req.action_id, action_id);
assert_eq!( assert_eq!(
active_req.target_id(), active_req.target_id(),
TargetAndApidId::new(TEST_APID, TEST_APID_TARGET_ID).raw() UniqueApidTargetId::new(TEST_APID, TEST_UNIQUE_ID).raw()
); );
assert_eq!( assert_eq!(
active_req.token().request_id(), active_req.token().request_id(),
@ -606,14 +565,14 @@ mod tests {
let action_id = 5_u32; let action_id = 5_u32;
let mut app_data: [u8; 16] = [0; 16]; let mut app_data: [u8; 16] = [0; 16];
// Invalid ID, routing should fail. // Invalid ID, routing should fail.
app_data[0..4].copy_from_slice(&TEST_APID_TARGET_ID.to_be_bytes()); app_data[0..4].copy_from_slice(&TEST_UNIQUE_ID.to_be_bytes());
app_data[4..8].copy_from_slice(&action_id.to_be_bytes()); app_data[4..8].copy_from_slice(&action_id.to_be_bytes());
for i in 0..8 { for i in 0..8 {
app_data[i + 8] = i as u8; app_data[i + 8] = i as u8;
} }
let pus8_packet = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true); let pus8_packet = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true);
let token = testbench.add_tc(&pus8_packet); let token = testbench.add_tc(&pus8_packet);
let result = testbench.convert(token, &[], TEST_APID, TEST_APID_TARGET_ID); let result = testbench.convert(token, &[], TEST_APID, TEST_UNIQUE_ID);
assert!(result.is_ok()); assert!(result.is_ok());
let (active_req, request) = result.unwrap(); let (active_req, request) = result.unwrap();
if let ActionRequestVariant::VecData(vec) = request.variant { if let ActionRequestVariant::VecData(vec) = request.variant {
@ -629,24 +588,26 @@ mod tests {
fn reply_handling_completion_success() { fn reply_handling_completion_success() {
let mut testbench = ReplyHandlerTestbench::new(ActionReplyHandler::default()); let mut testbench = ReplyHandlerTestbench::new(ActionReplyHandler::default());
let action_id = 5_u32; let action_id = 5_u32;
let (req_id, active_req) = testbench.add_tc(TEST_APID, TEST_APID_TARGET_ID, &[]); let (req_id, active_req) = testbench.add_tc(TEST_APID, TEST_UNIQUE_ID, &[]);
let active_action_req = let active_action_req =
ActivePusActionRequestStd::new_from_common_req(action_id, active_req); ActivePusActionRequestStd::new_from_common_req(action_id, active_req);
let reply = PusActionReply::new(action_id, ActionReplyVariant::Completed); let reply = PusActionReply::new(action_id, ActionReplyVariant::Completed);
let generic_reply = GenericMessage::new(req_id.into(), 0, reply); let generic_reply = GenericMessage::new(MessageMetadata::new(req_id.into(), 0), reply);
let result = testbench.handle_reply(&generic_reply, &active_action_req, &[]); let result = testbench.handle_reply(&generic_reply, &active_action_req, &[]);
assert!(result.is_ok()); assert!(result.is_ok());
assert!(result.unwrap()); assert!(result.unwrap());
testbench testbench.verif_reporter.assert_full_completion_success(
.verif_reporter TEST_COMPONENT_ID.raw(),
.assert_full_completion_success(&req_id, None); req_id,
None,
);
} }
#[test] #[test]
fn reply_handling_completion_failure() { fn reply_handling_completion_failure() {
let mut testbench = ReplyHandlerTestbench::new(ActionReplyHandler::default()); let mut testbench = ReplyHandlerTestbench::new(ActionReplyHandler::default());
let action_id = 5_u32; let action_id = 5_u32;
let (req_id, active_req) = testbench.add_tc(TEST_APID, TEST_APID_TARGET_ID, &[]); let (req_id, active_req) = testbench.add_tc(TEST_APID, TEST_UNIQUE_ID, &[]);
let active_action_req = let active_action_req =
ActivePusActionRequestStd::new_from_common_req(action_id, active_req); ActivePusActionRequestStd::new_from_common_req(action_id, active_req);
let error_code = ResultU16::new(2, 3); let error_code = ResultU16::new(2, 3);
@ -657,40 +618,48 @@ mod tests {
params: None, params: None,
}, },
); );
let generic_reply = GenericMessage::new(req_id.into(), 0, reply); let generic_reply = GenericMessage::new(MessageMetadata::new(req_id.into(), 0), reply);
let result = testbench.handle_reply(&generic_reply, &active_action_req, &[]); let result = testbench.handle_reply(&generic_reply, &active_action_req, &[]);
assert!(result.is_ok()); assert!(result.is_ok());
assert!(result.unwrap()); assert!(result.unwrap());
testbench testbench.verif_reporter.assert_completion_failure(
.verif_reporter TEST_COMPONENT_ID.into(),
.assert_completion_failure(&req_id, None, error_code.raw() as u64); req_id,
None,
error_code.raw() as u64,
);
} }
#[test] #[test]
fn reply_handling_step_success() { fn reply_handling_step_success() {
let mut testbench = ReplyHandlerTestbench::new(ActionReplyHandler::default()); let mut testbench = ReplyHandlerTestbench::new(ActionReplyHandler::default());
let action_id = 5_u32; let action_id = 5_u32;
let (req_id, active_req) = testbench.add_tc(TEST_APID, TEST_APID_TARGET_ID, &[]); let (req_id, active_req) = testbench.add_tc(TEST_APID, TEST_UNIQUE_ID, &[]);
let active_action_req = let active_action_req =
ActivePusActionRequestStd::new_from_common_req(action_id, active_req); ActivePusActionRequestStd::new_from_common_req(action_id, active_req);
let reply = PusActionReply::new(action_id, ActionReplyVariant::StepSuccess { step: 1 }); let reply = PusActionReply::new(action_id, ActionReplyVariant::StepSuccess { step: 1 });
let generic_reply = GenericMessage::new(req_id.into(), 0, reply); let generic_reply = GenericMessage::new(MessageMetadata::new(req_id.into(), 0), reply);
let result = testbench.handle_reply(&generic_reply, &active_action_req, &[]); let result = testbench.handle_reply(&generic_reply, &active_action_req, &[]);
assert!(result.is_ok()); assert!(result.is_ok());
// Entry should not be removed, completion not done yet. // Entry should not be removed, completion not done yet.
assert!(!result.unwrap()); assert!(!result.unwrap());
let verif_info = testbench.verif_reporter.verification_info(&req_id); testbench.verif_reporter.check_next_was_added(req_id);
assert!(verif_info.is_some()); testbench
let verif_info = verif_info.unwrap(); .verif_reporter
assert!(verif_info.step_status.unwrap()); .check_next_is_acceptance_success(TEST_COMPONENT_ID.raw(), req_id);
assert_eq!(verif_info.step, 1); testbench
.verif_reporter
.check_next_is_started_success(TEST_COMPONENT_ID.raw(), req_id);
testbench
.verif_reporter
.check_next_is_step_success(TEST_COMPONENT_ID.raw(), req_id, 1);
} }
#[test] #[test]
fn reply_handling_step_failure() { fn reply_handling_step_failure() {
let mut testbench = ReplyHandlerTestbench::new(ActionReplyHandler::default()); let mut testbench = ReplyHandlerTestbench::new(ActionReplyHandler::default());
let action_id = 5_u32; let action_id = 5_u32;
let (req_id, active_req) = testbench.add_tc(TEST_APID, TEST_APID_TARGET_ID, &[]); let (req_id, active_req) = testbench.add_tc(TEST_APID, TEST_UNIQUE_ID, &[]);
let active_action_req = let active_action_req =
ActivePusActionRequestStd::new_from_common_req(action_id, active_req); ActivePusActionRequestStd::new_from_common_req(action_id, active_req);
let error_code = ResultU16::new(2, 3); let error_code = ResultU16::new(2, 3);
@ -702,22 +671,28 @@ mod tests {
params: None, params: None,
}, },
); );
let generic_reply = GenericMessage::new(req_id.into(), 0, reply); let generic_reply = GenericMessage::new(MessageMetadata::new(req_id.into(), 0), reply);
let result = testbench.handle_reply(&generic_reply, &active_action_req, &[]); let result = testbench.handle_reply(&generic_reply, &active_action_req, &[]);
assert!(result.is_ok()); assert!(result.is_ok());
assert!(result.unwrap()); assert!(result.unwrap());
let verif_info = testbench.verif_reporter.verification_info(&req_id); testbench.verif_reporter.check_next_was_added(req_id);
assert!(verif_info.is_some()); testbench
let verif_info = verif_info.unwrap(); .verif_reporter
assert!(!verif_info.step_status.unwrap()); .check_next_is_acceptance_success(TEST_COMPONENT_ID.raw(), req_id);
assert_eq!(verif_info.step, 1); testbench
.verif_reporter
.check_next_is_started_success(TEST_COMPONENT_ID.raw(), req_id);
testbench
.verif_reporter
.check_next_is_step_success(TEST_COMPONENT_ID.raw(), req_id, 1);
} }
#[test] #[test]
fn reply_handling_unrequested_reply() { fn reply_handling_unrequested_reply() {
let mut testbench = ReplyHandlerTestbench::new(ActionReplyHandler::default()); let mut testbench = ReplyHandlerTestbench::new(ActionReplyHandler::default());
let action_reply = PusActionReply::new(5_u32, ActionReplyVariant::Completed); let action_reply = PusActionReply::new(5_u32, ActionReplyVariant::Completed);
let unrequested_reply = GenericMessage::new(10_u32, 15_u64, action_reply); let unrequested_reply =
GenericMessage::new(MessageMetadata::new(10_u32, 15_u64), action_reply);
// Right now this function does not do a lot. We simply check that it does not panic or do // Right now this function does not do a lot. We simply check that it does not panic or do
// weird stuff. // weird stuff.
let result = testbench.handle_unrequested_reply(&unrequested_reply); let result = testbench.handle_unrequested_reply(&unrequested_reply);
@ -727,9 +702,18 @@ mod tests {
#[test] #[test]
fn reply_handling_reply_timeout() { fn reply_handling_reply_timeout() {
let mut testbench = ReplyHandlerTestbench::new(ActionReplyHandler::default()); let mut testbench = ReplyHandlerTestbench::new(ActionReplyHandler::default());
// TODO: Start a request, then time it out with the API and check verification completion let action_id = 5_u32;
// failure. let (req_id, active_request) = testbench.add_tc(TEST_APID, TEST_UNIQUE_ID, &[]);
// testbench.reply_handler.handle_request_timeout(active_request, verification_handler, time_stamp, tm_sender) let result = testbench.handle_request_timeout(
// testbench.default_timeout = Duration::from_millis(50); &ActivePusActionRequestStd::new_from_common_req(action_id, active_request),
&[],
);
assert!(result.is_ok());
testbench.verif_reporter.assert_completion_failure(
TEST_COMPONENT_ID.raw(),
req_id,
None,
tmtc_err::REQUEST_TIMEOUT.raw() as u64,
);
} }
} }

View File

@ -1,114 +1,66 @@
use std::sync::mpsc; use std::sync::mpsc;
use crate::pus::create_verification_reporter;
use log::{error, warn}; use log::{error, warn};
use satrs::pool::{SharedStaticMemoryPool, StoreAddr}; use satrs::pool::SharedStaticMemoryPool;
use satrs::pus::event_man::EventRequestWithToken; use satrs::pus::event_man::EventRequestWithToken;
use satrs::pus::event_srv::PusService5EventHandler; use satrs::pus::event_srv::PusEventServiceHandler;
use satrs::pus::verification::std_mod::{ use satrs::pus::verification::VerificationReporter;
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender,
};
use satrs::pus::verification::VerificationReportingProvider;
use satrs::pus::{ use satrs::pus::{
EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter,
EcssTcReceiverCore, EcssTmSenderCore, MpscTcReceiver, PusPacketHandlerResult, PusServiceHelper, EcssTmSenderCore, MpscTcReceiver, MpscTmAsVecSender, MpscTmInSharedPoolSenderBounded,
TmAsVecSenderWithId, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, PusPacketHandlerResult, PusServiceHelper, PusTmAsVec, PusTmInPool, TmInSharedPoolSender,
TmInSharedPoolSenderWithId,
}; };
use satrs::tmtc::tm_helper::SharedTmPool; use satrs_example::config::components::PUS_EVENT_MANAGEMENT;
use satrs::ComponentId;
use satrs_example::config::{ComponentIdList, PUS_APID};
pub fn create_event_service_static( pub fn create_event_service_static(
shared_tm_store: SharedTmPool, tm_sender: TmInSharedPoolSender<mpsc::SyncSender<PusTmInPool>>,
tm_funnel_tx: mpsc::SyncSender<StoreAddr>,
verif_reporter: VerificationReporterWithSharedPoolMpscBoundedSender,
tc_pool: SharedStaticMemoryPool, tc_pool: SharedStaticMemoryPool,
pus_event_rx: mpsc::Receiver<EcssTcAndToken>, pus_event_rx: mpsc::Receiver<EcssTcAndToken>,
event_request_tx: mpsc::Sender<EventRequestWithToken>, event_request_tx: mpsc::Sender<EventRequestWithToken>,
) -> Pus5Wrapper< ) -> EventServiceWrapper<MpscTmInSharedPoolSenderBounded, EcssTcInSharedStoreConverter> {
MpscTcReceiver, let pus_5_handler = PusEventServiceHandler::new(
TmInSharedPoolSenderWithBoundedMpsc,
EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender,
> {
let event_srv_tm_sender = TmInSharedPoolSenderWithId::new(
ComponentIdList::EventManagement as ComponentId,
"PUS_5_TM_SENDER",
shared_tm_store.clone(),
tm_funnel_tx.clone(),
);
let event_srv_receiver = MpscTcReceiver::new(
ComponentIdList::EventManagement as ComponentId,
"PUS_5_TC_RECV",
pus_event_rx,
);
let pus_5_handler = PusService5EventHandler::new(
PusServiceHelper::new( PusServiceHelper::new(
event_srv_receiver, PUS_EVENT_MANAGEMENT.raw(),
event_srv_tm_sender, pus_event_rx,
PUS_APID, tm_sender,
verif_reporter.clone(), create_verification_reporter(PUS_EVENT_MANAGEMENT.apid),
EcssTcInSharedStoreConverter::new(tc_pool.clone(), 2048), EcssTcInSharedStoreConverter::new(tc_pool.clone(), 2048),
), ),
event_request_tx, event_request_tx,
); );
Pus5Wrapper { EventServiceWrapper {
handler: pus_5_handler, handler: pus_5_handler,
} }
} }
pub fn create_event_service_dynamic( pub fn create_event_service_dynamic(
tm_funnel_tx: mpsc::Sender<Vec<u8>>, tm_funnel_tx: mpsc::Sender<PusTmAsVec>,
verif_reporter: VerificationReporterWithVecMpscSender,
pus_event_rx: mpsc::Receiver<EcssTcAndToken>, pus_event_rx: mpsc::Receiver<EcssTcAndToken>,
event_request_tx: mpsc::Sender<EventRequestWithToken>, event_request_tx: mpsc::Sender<EventRequestWithToken>,
) -> Pus5Wrapper< ) -> EventServiceWrapper<MpscTmAsVecSender, EcssTcInVecConverter> {
MpscTcReceiver, let pus_5_handler = PusEventServiceHandler::new(
TmAsVecSenderWithMpsc,
EcssTcInVecConverter,
VerificationReporterWithVecMpscSender,
> {
let event_srv_tm_sender = TmAsVecSenderWithId::new(
ComponentIdList::EventManagement as ComponentId,
"PUS_5_TM_SENDER",
tm_funnel_tx,
);
let event_srv_receiver = MpscTcReceiver::new(
ComponentIdList::EventManagement as ComponentId,
"PUS_5_TC_RECV",
pus_event_rx,
);
let pus_5_handler = PusService5EventHandler::new(
PusServiceHelper::new( PusServiceHelper::new(
event_srv_receiver, PUS_EVENT_MANAGEMENT.raw(),
event_srv_tm_sender, pus_event_rx,
PUS_APID, tm_funnel_tx,
verif_reporter.clone(), create_verification_reporter(PUS_EVENT_MANAGEMENT.apid),
EcssTcInVecConverter::default(), EcssTcInVecConverter::default(),
), ),
event_request_tx, event_request_tx,
); );
Pus5Wrapper { EventServiceWrapper {
handler: pus_5_handler, handler: pus_5_handler,
} }
} }
pub struct Pus5Wrapper< pub struct EventServiceWrapper<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter> {
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> {
pub handler: pub handler:
PusService5EventHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>, PusEventServiceHandler<MpscTcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
} }
impl< impl<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter>
TcReceiver: EcssTcReceiverCore, EventServiceWrapper<TmSender, TcInMemConverter>
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> Pus5Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{ {
pub fn poll_and_handle_next_tc(&mut self, time_stamp: &[u8]) -> bool { pub fn poll_and_handle_next_tc(&mut self, time_stamp: &[u8]) -> bool {
match self.handler.poll_and_handle_next_tc(time_stamp) { match self.handler.poll_and_handle_next_tc(time_stamp) {

View File

@ -1,30 +1,28 @@
use derive_new::new; use derive_new::new;
use log::{error, warn}; use log::{error, warn};
use satrs::hk::{CollectionIntervalFactor, HkRequest, HkRequestVariant, UniqueId}; use satrs::hk::{CollectionIntervalFactor, HkRequest, HkRequestVariant, UniqueId};
use satrs::pool::{SharedStaticMemoryPool, StoreAddr}; use satrs::pool::SharedStaticMemoryPool;
use satrs::pus::verification::{ use satrs::pus::verification::{
FailParams, TcStateAccepted, TcStateStarted, FailParams, TcStateAccepted, TcStateStarted, VerificationReporter,
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender,
VerificationReportingProvider, VerificationToken, VerificationReportingProvider, VerificationToken,
}; };
use satrs::pus::{ use satrs::pus::{
ActivePusRequestStd, ActiveRequestProvider, DefaultActiveRequestMap, EcssTcAndToken, ActivePusRequestStd, ActiveRequestProvider, DefaultActiveRequestMap, EcssTcAndToken,
EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiverCore, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTmSenderCore,
EcssTmSenderCore, EcssTmtcError, GenericConversionError, MpscTcReceiver, EcssTmtcError, GenericConversionError, MpscTcReceiver, MpscTmAsVecSender,
PusPacketHandlerResult, PusReplyHandler, PusServiceHelper, PusTcToRequestConverter, MpscTmInSharedPoolSenderBounded, PusPacketHandlerResult, PusReplyHandler, PusServiceHelper,
TmAsVecSenderWithId, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, PusTcToRequestConverter, PusTmAsVec, PusTmInPool, TmInSharedPoolSender,
TmInSharedPoolSenderWithId,
}; };
use satrs::request::{GenericMessage, TargetAndApidId}; use satrs::request::{GenericMessage, UniqueApidTargetId};
use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::{hk, PusPacket}; use satrs::spacepackets::ecss::{hk, PusPacket};
use satrs::tmtc::tm_helper::SharedTmPool;
use satrs::ComponentId; use satrs::ComponentId;
use satrs_example::config::{hk_err, tmtc_err, ComponentIdList, PUS_APID}; use satrs_example::config::components::PUS_HK_SERVICE;
use std::sync::mpsc::{self}; use satrs_example::config::{hk_err, tmtc_err};
use std::sync::mpsc;
use std::time::Duration; use std::time::Duration;
use crate::pus::generic_pus_request_timeout_handler; use crate::pus::{create_verification_reporter, generic_pus_request_timeout_handler};
use crate::requests::GenericRequestRouter; use crate::requests::GenericRequestRouter;
use super::PusTargetedRequestService; use super::PusTargetedRequestService;
@ -48,7 +46,8 @@ impl PusReplyHandler<ActivePusRequestStd, HkReply> for HkReplyHandler {
fn handle_unrequested_reply( fn handle_unrequested_reply(
&mut self, &mut self,
reply: &satrs::request::GenericMessage<HkReply>, _caller_id: ComponentId,
reply: &GenericMessage<HkReply>,
_tm_sender: &impl EcssTmSenderCore, _tm_sender: &impl EcssTmSenderCore,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
log::warn!("received unexpected reply for service 3: {reply:?}"); log::warn!("received unexpected reply for service 3: {reply:?}");
@ -57,11 +56,12 @@ impl PusReplyHandler<ActivePusRequestStd, HkReply> for HkReplyHandler {
fn handle_reply( fn handle_reply(
&mut self, &mut self,
reply: &satrs::request::GenericMessage<HkReply>, caller_id: ComponentId,
reply: &GenericMessage<HkReply>,
active_request: &ActivePusRequestStd, active_request: &ActivePusRequestStd,
tm_sender: &impl EcssTmSenderCore,
verification_handler: &impl VerificationReportingProvider, verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8], time_stamp: &[u8],
_tm_sender: &impl EcssTmSenderCore,
) -> Result<bool, Self::Error> { ) -> Result<bool, Self::Error> {
let started_token: VerificationToken<TcStateStarted> = active_request let started_token: VerificationToken<TcStateStarted> = active_request
.token() .token()
@ -70,8 +70,8 @@ impl PusReplyHandler<ActivePusRequestStd, HkReply> for HkReplyHandler {
match reply.message.variant { match reply.message.variant {
HkReplyVariant::Ack => { HkReplyVariant::Ack => {
verification_handler verification_handler
.completion_success(started_token, time_stamp) .completion_success(caller_id, tm_sender, started_token, time_stamp)
.expect("sending completio success verification failed"); .expect("sending completion success verification failed");
} }
}; };
Ok(true) Ok(true)
@ -79,12 +79,15 @@ impl PusReplyHandler<ActivePusRequestStd, HkReply> for HkReplyHandler {
fn handle_request_timeout( fn handle_request_timeout(
&mut self, &mut self,
caller_id: ComponentId,
active_request: &ActivePusRequestStd, active_request: &ActivePusRequestStd,
tm_sender: &impl EcssTmSenderCore,
verification_handler: &impl VerificationReportingProvider, verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8], time_stamp: &[u8],
_tm_sender: &impl EcssTmSenderCore,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
generic_pus_request_timeout_handler( generic_pus_request_timeout_handler(
caller_id,
tm_sender,
active_request, active_request,
verification_handler, verification_handler,
time_stamp, time_stamp,
@ -111,10 +114,12 @@ impl PusTcToRequestConverter<ActivePusRequestStd, HkRequest> for HkRequestConver
fn convert( fn convert(
&mut self, &mut self,
caller_id: ComponentId,
token: VerificationToken<TcStateAccepted>, token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader, tc: &PusTcReader,
time_stamp: &[u8], tm_sender: &(impl EcssTmSenderCore + ?Sized),
verif_reporter: &impl VerificationReportingProvider, verif_reporter: &impl VerificationReportingProvider,
time_stamp: &[u8],
) -> Result<(ActivePusRequestStd, HkRequest), Self::Error> { ) -> Result<(ActivePusRequestStd, HkRequest), Self::Error> {
let user_data = tc.user_data(); let user_data = tc.user_data();
if user_data.is_empty() { if user_data.is_empty() {
@ -122,6 +127,8 @@ impl PusTcToRequestConverter<ActivePusRequestStd, HkRequest> for HkRequestConver
let user_data_len_raw = user_data_len.to_be_bytes(); let user_data_len_raw = user_data_len.to_be_bytes();
verif_reporter verif_reporter
.start_failure( .start_failure(
caller_id,
tm_sender,
token, token,
FailParams::new( FailParams::new(
time_stamp, time_stamp,
@ -144,7 +151,12 @@ impl PusTcToRequestConverter<ActivePusRequestStd, HkRequest> for HkRequestConver
let user_data_len = user_data.len() as u32; let user_data_len = user_data.len() as u32;
let user_data_len_raw = user_data_len.to_be_bytes(); let user_data_len_raw = user_data_len.to_be_bytes();
verif_reporter verif_reporter
.start_failure(token, FailParams::new(time_stamp, err, &user_data_len_raw)) .start_failure(
caller_id,
tm_sender,
token,
FailParams::new(time_stamp, err, &user_data_len_raw),
)
.expect("Sending start failure TM failed"); .expect("Sending start failure TM failed");
return Err(GenericConversionError::NotEnoughAppData { return Err(GenericConversionError::NotEnoughAppData {
expected: 8, expected: 8,
@ -152,13 +164,15 @@ impl PusTcToRequestConverter<ActivePusRequestStd, HkRequest> for HkRequestConver
}); });
} }
let subservice = tc.subservice(); let subservice = tc.subservice();
let target_id_and_apid = TargetAndApidId::from_pus_tc(tc).expect("invalid tc format"); let target_id_and_apid = UniqueApidTargetId::from_pus_tc(tc).expect("invalid tc format");
let unique_id = u32::from_be_bytes(tc.user_data()[4..8].try_into().unwrap()); let unique_id = u32::from_be_bytes(tc.user_data()[4..8].try_into().unwrap());
let standard_subservice = hk::Subservice::try_from(subservice); let standard_subservice = hk::Subservice::try_from(subservice);
if standard_subservice.is_err() { if standard_subservice.is_err() {
verif_reporter verif_reporter
.start_failure( .start_failure(
caller_id,
tm_sender,
token, token,
FailParams::new(time_stamp, &tmtc_err::INVALID_PUS_SUBSERVICE, &[subservice]), FailParams::new(time_stamp, &tmtc_err::INVALID_PUS_SUBSERVICE, &[subservice]),
) )
@ -167,10 +181,10 @@ impl PusTcToRequestConverter<ActivePusRequestStd, HkRequest> for HkRequestConver
} }
let request = match standard_subservice.unwrap() { let request = match standard_subservice.unwrap() {
hk::Subservice::TcEnableHkGeneration | hk::Subservice::TcEnableDiagGeneration => { hk::Subservice::TcEnableHkGeneration | hk::Subservice::TcEnableDiagGeneration => {
HkRequest::new(unique_id, HkRequestVariant::Enable) HkRequest::new(unique_id, HkRequestVariant::EnablePeriodic)
} }
hk::Subservice::TcDisableHkGeneration | hk::Subservice::TcDisableDiagGeneration => { hk::Subservice::TcDisableHkGeneration | hk::Subservice::TcDisableDiagGeneration => {
HkRequest::new(unique_id, HkRequestVariant::Disable) HkRequest::new(unique_id, HkRequestVariant::DisablePeriodic)
} }
hk::Subservice::TcReportHkReportStructures => todo!(), hk::Subservice::TcReportHkReportStructures => todo!(),
hk::Subservice::TmHkPacket => todo!(), hk::Subservice::TmHkPacket => todo!(),
@ -182,6 +196,8 @@ impl PusTcToRequestConverter<ActivePusRequestStd, HkRequest> for HkRequestConver
if user_data.len() < 12 { if user_data.len() < 12 {
verif_reporter verif_reporter
.start_failure( .start_failure(
caller_id,
tm_sender,
token, token,
FailParams::new_no_fail_data( FailParams::new_no_fail_data(
time_stamp, time_stamp,
@ -206,6 +222,8 @@ impl PusTcToRequestConverter<ActivePusRequestStd, HkRequest> for HkRequestConver
_ => { _ => {
verif_reporter verif_reporter
.start_failure( .start_failure(
caller_id,
tm_sender,
token, token,
FailParams::new( FailParams::new(
time_stamp, time_stamp,
@ -225,37 +243,18 @@ impl PusTcToRequestConverter<ActivePusRequestStd, HkRequest> for HkRequestConver
} }
pub fn create_hk_service_static( pub fn create_hk_service_static(
shared_tm_store: SharedTmPool, tm_sender: TmInSharedPoolSender<mpsc::SyncSender<PusTmInPool>>,
tm_funnel_tx: mpsc::SyncSender<StoreAddr>,
verif_reporter: VerificationReporterWithSharedPoolMpscBoundedSender,
tc_pool: SharedStaticMemoryPool, tc_pool: SharedStaticMemoryPool,
pus_hk_rx: mpsc::Receiver<EcssTcAndToken>, pus_hk_rx: mpsc::Receiver<EcssTcAndToken>,
request_router: GenericRequestRouter, request_router: GenericRequestRouter,
reply_receiver: mpsc::Receiver<GenericMessage<HkReply>>, reply_receiver: mpsc::Receiver<GenericMessage<HkReply>>,
) -> Pus3Wrapper< ) -> HkServiceWrapper<MpscTmInSharedPoolSenderBounded, EcssTcInSharedStoreConverter> {
MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc,
EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender,
> {
let hk_srv_tm_sender = TmInSharedPoolSenderWithId::new(
ComponentIdList::PusHk as ComponentId,
"PUS_3_TM_SENDER",
shared_tm_store.clone(),
tm_funnel_tx.clone(),
);
let hk_srv_receiver = MpscTcReceiver::new(
ComponentIdList::PusHk as ComponentId,
"PUS_8_TC_RECV",
pus_hk_rx,
);
let pus_3_handler = PusTargetedRequestService::new( let pus_3_handler = PusTargetedRequestService::new(
ComponentIdList::PusHk as ComponentId,
PusServiceHelper::new( PusServiceHelper::new(
hk_srv_receiver, PUS_HK_SERVICE.raw(),
hk_srv_tm_sender, pus_hk_rx,
PUS_APID, tm_sender,
verif_reporter.clone(), create_verification_reporter(PUS_HK_SERVICE.apid),
EcssTcInSharedStoreConverter::new(tc_pool, 2048), EcssTcInSharedStoreConverter::new(tc_pool, 2048),
), ),
HkRequestConverter::default(), HkRequestConverter::default(),
@ -264,40 +263,23 @@ pub fn create_hk_service_static(
request_router, request_router,
reply_receiver, reply_receiver,
); );
Pus3Wrapper { HkServiceWrapper {
service: pus_3_handler, service: pus_3_handler,
} }
} }
pub fn create_hk_service_dynamic( pub fn create_hk_service_dynamic(
tm_funnel_tx: mpsc::Sender<Vec<u8>>, tm_funnel_tx: mpsc::Sender<PusTmAsVec>,
verif_reporter: VerificationReporterWithVecMpscSender,
pus_hk_rx: mpsc::Receiver<EcssTcAndToken>, pus_hk_rx: mpsc::Receiver<EcssTcAndToken>,
request_router: GenericRequestRouter, request_router: GenericRequestRouter,
reply_receiver: mpsc::Receiver<GenericMessage<HkReply>>, reply_receiver: mpsc::Receiver<GenericMessage<HkReply>>,
) -> Pus3Wrapper< ) -> HkServiceWrapper<MpscTmAsVecSender, EcssTcInVecConverter> {
MpscTcReceiver,
TmAsVecSenderWithMpsc,
EcssTcInVecConverter,
VerificationReporterWithVecMpscSender,
> {
let hk_srv_tm_sender = TmAsVecSenderWithId::new(
ComponentIdList::PusHk as ComponentId,
"PUS_3_TM_SENDER",
tm_funnel_tx.clone(),
);
let hk_srv_receiver = MpscTcReceiver::new(
ComponentIdList::PusHk as ComponentId,
"PUS_8_TC_RECV",
pus_hk_rx,
);
let pus_3_handler = PusTargetedRequestService::new( let pus_3_handler = PusTargetedRequestService::new(
ComponentIdList::PusHk as ComponentId,
PusServiceHelper::new( PusServiceHelper::new(
hk_srv_receiver, PUS_HK_SERVICE.raw(),
hk_srv_tm_sender, pus_hk_rx,
PUS_APID, tm_funnel_tx,
verif_reporter.clone(), create_verification_reporter(PUS_HK_SERVICE.apid),
EcssTcInVecConverter::default(), EcssTcInVecConverter::default(),
), ),
HkRequestConverter::default(), HkRequestConverter::default(),
@ -306,19 +288,14 @@ pub fn create_hk_service_dynamic(
request_router, request_router,
reply_receiver, reply_receiver,
); );
Pus3Wrapper { HkServiceWrapper {
service: pus_3_handler, service: pus_3_handler,
} }
} }
pub struct Pus3Wrapper< pub struct HkServiceWrapper<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter> {
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> {
pub(crate) service: PusTargetedRequestService< pub(crate) service: PusTargetedRequestService<
TcReceiver, MpscTcReceiver,
TmSender, TmSender,
TcInMemConverter, TcInMemConverter,
VerificationReporter, VerificationReporter,
@ -331,12 +308,8 @@ pub struct Pus3Wrapper<
>, >,
} }
impl< impl<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter>
TcReceiver: EcssTcReceiverCore, HkServiceWrapper<TmSender, TcInMemConverter>
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> Pus3Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{ {
pub fn poll_and_handle_next_tc(&mut self, time_stamp: &[u8]) -> bool { pub fn poll_and_handle_next_tc(&mut self, time_stamp: &[u8]) -> bool {
match self.service.poll_and_handle_next_tc(time_stamp) { match self.service.poll_and_handle_next_tc(time_stamp) {
@ -363,13 +336,12 @@ impl<
} }
pub fn poll_and_handle_next_reply(&mut self, time_stamp: &[u8]) -> bool { pub fn poll_and_handle_next_reply(&mut self, time_stamp: &[u8]) -> bool {
match self.service.poll_and_check_next_reply(time_stamp) { self.service
Ok(packet_handled) => packet_handled, .poll_and_check_next_reply(time_stamp)
Err(e) => { .unwrap_or_else(|e| {
log::warn!("PUS 3: Handling reply failed with error {e:?}"); warn!("PUS 3: Handling reply failed with error {e:?}");
false false
} })
}
} }
pub fn check_for_request_timeouts(&mut self) { pub fn check_for_request_timeouts(&mut self) {
@ -379,6 +351,8 @@ impl<
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use satrs::pus::test_util::{TEST_COMPONENT_ID, TEST_UNIQUE_ID};
use satrs::request::MessageMetadata;
use satrs::{ use satrs::{
hk::HkRequestVariant, hk::HkRequestVariant,
pus::test_util::TEST_APID, pus::test_util::TEST_APID,
@ -388,10 +362,11 @@ mod tests {
SpHeader, SpHeader,
}, },
}; };
use satrs_example::config::tmtc_err;
use crate::pus::{ use crate::pus::{
hk::HkReplyVariant, hk::HkReplyVariant,
tests::{PusConverterTestbench, ReplyHandlerTestbench, TEST_APID_TARGET_ID}, tests::{PusConverterTestbench, ReplyHandlerTestbench},
}; };
use super::{HkReply, HkReplyHandler, HkRequestConverter}; use super::{HkReply, HkReplyHandler, HkRequestConverter};
@ -400,7 +375,7 @@ mod tests {
fn hk_converter_one_shot_req() { fn hk_converter_one_shot_req() {
let mut hk_bench = PusConverterTestbench::new(HkRequestConverter::default()); let mut hk_bench = PusConverterTestbench::new(HkRequestConverter::default());
let mut sp_header = SpHeader::tc_unseg(TEST_APID, 0, 0).unwrap(); let mut sp_header = SpHeader::tc_unseg(TEST_APID, 0, 0).unwrap();
let target_id = TEST_APID_TARGET_ID; let target_id = TEST_UNIQUE_ID;
let unique_id = 5_u32; let unique_id = 5_u32;
let mut app_data: [u8; 8] = [0; 8]; let mut app_data: [u8; 8] = [0; 8];
app_data[0..4].copy_from_slice(&target_id.to_be_bytes()); app_data[0..4].copy_from_slice(&target_id.to_be_bytes());
@ -415,7 +390,7 @@ mod tests {
); );
let accepted_token = hk_bench.add_tc(&hk_req); let accepted_token = hk_bench.add_tc(&hk_req);
let (_active_req, req) = hk_bench let (_active_req, req) = hk_bench
.convert(accepted_token, &[], TEST_APID, TEST_APID_TARGET_ID) .convert(accepted_token, &[], TEST_APID, TEST_UNIQUE_ID)
.expect("conversion failed"); .expect("conversion failed");
assert_eq!(req.unique_id, unique_id); assert_eq!(req.unique_id, unique_id);
@ -429,7 +404,7 @@ mod tests {
fn hk_converter_enable_periodic_generation() { fn hk_converter_enable_periodic_generation() {
let mut hk_bench = PusConverterTestbench::new(HkRequestConverter::default()); let mut hk_bench = PusConverterTestbench::new(HkRequestConverter::default());
let mut sp_header = SpHeader::tc_unseg(TEST_APID, 0, 0).unwrap(); let mut sp_header = SpHeader::tc_unseg(TEST_APID, 0, 0).unwrap();
let target_id = TEST_APID_TARGET_ID; let target_id = TEST_UNIQUE_ID;
let unique_id = 5_u32; let unique_id = 5_u32;
let mut app_data: [u8; 8] = [0; 8]; let mut app_data: [u8; 8] = [0; 8];
app_data[0..4].copy_from_slice(&target_id.to_be_bytes()); app_data[0..4].copy_from_slice(&target_id.to_be_bytes());
@ -437,10 +412,10 @@ mod tests {
let mut generic_check = |tc: &PusTcCreator| { let mut generic_check = |tc: &PusTcCreator| {
let accepted_token = hk_bench.add_tc(tc); let accepted_token = hk_bench.add_tc(tc);
let (_active_req, req) = hk_bench let (_active_req, req) = hk_bench
.convert(accepted_token, &[], TEST_APID, TEST_APID_TARGET_ID) .convert(accepted_token, &[], TEST_APID, TEST_UNIQUE_ID)
.expect("conversion failed"); .expect("conversion failed");
assert_eq!(req.unique_id, unique_id); assert_eq!(req.unique_id, unique_id);
if let HkRequestVariant::Enable = req.variant { if let HkRequestVariant::EnablePeriodic = req.variant {
} else { } else {
panic!("unexpected HK request") panic!("unexpected HK request")
} }
@ -467,7 +442,7 @@ mod tests {
fn hk_conversion_disable_periodic_generation() { fn hk_conversion_disable_periodic_generation() {
let mut hk_bench = PusConverterTestbench::new(HkRequestConverter::default()); let mut hk_bench = PusConverterTestbench::new(HkRequestConverter::default());
let mut sp_header = SpHeader::tc_unseg(TEST_APID, 0, 0).unwrap(); let mut sp_header = SpHeader::tc_unseg(TEST_APID, 0, 0).unwrap();
let target_id = TEST_APID_TARGET_ID; let target_id = TEST_UNIQUE_ID;
let unique_id = 5_u32; let unique_id = 5_u32;
let mut app_data: [u8; 8] = [0; 8]; let mut app_data: [u8; 8] = [0; 8];
app_data[0..4].copy_from_slice(&target_id.to_be_bytes()); app_data[0..4].copy_from_slice(&target_id.to_be_bytes());
@ -475,10 +450,10 @@ mod tests {
let mut generic_check = |tc: &PusTcCreator| { let mut generic_check = |tc: &PusTcCreator| {
let accepted_token = hk_bench.add_tc(tc); let accepted_token = hk_bench.add_tc(tc);
let (_active_req, req) = hk_bench let (_active_req, req) = hk_bench
.convert(accepted_token, &[], TEST_APID, TEST_APID_TARGET_ID) .convert(accepted_token, &[], TEST_APID, TEST_UNIQUE_ID)
.expect("conversion failed"); .expect("conversion failed");
assert_eq!(req.unique_id, unique_id); assert_eq!(req.unique_id, unique_id);
if let HkRequestVariant::Disable = req.variant { if let HkRequestVariant::DisablePeriodic = req.variant {
} else { } else {
panic!("unexpected HK request") panic!("unexpected HK request")
} }
@ -505,7 +480,7 @@ mod tests {
fn hk_conversion_modify_interval() { fn hk_conversion_modify_interval() {
let mut hk_bench = PusConverterTestbench::new(HkRequestConverter::default()); let mut hk_bench = PusConverterTestbench::new(HkRequestConverter::default());
let mut sp_header = SpHeader::tc_unseg(TEST_APID, 0, 0).unwrap(); let mut sp_header = SpHeader::tc_unseg(TEST_APID, 0, 0).unwrap();
let target_id = TEST_APID_TARGET_ID; let target_id = TEST_UNIQUE_ID;
let unique_id = 5_u32; let unique_id = 5_u32;
let mut app_data: [u8; 12] = [0; 12]; let mut app_data: [u8; 12] = [0; 12];
let collection_interval_factor = 5_u32; let collection_interval_factor = 5_u32;
@ -516,7 +491,7 @@ mod tests {
let mut generic_check = |tc: &PusTcCreator| { let mut generic_check = |tc: &PusTcCreator| {
let accepted_token = hk_bench.add_tc(tc); let accepted_token = hk_bench.add_tc(tc);
let (_active_req, req) = hk_bench let (_active_req, req) = hk_bench
.convert(accepted_token, &[], TEST_APID, TEST_APID_TARGET_ID) .convert(accepted_token, &[], TEST_APID, TEST_UNIQUE_ID)
.expect("conversion failed"); .expect("conversion failed");
assert_eq!(req.unique_id, unique_id); assert_eq!(req.unique_id, unique_id);
if let HkRequestVariant::ModifyCollectionInterval(interval_factor) = req.variant { if let HkRequestVariant::ModifyCollectionInterval(interval_factor) = req.variant {
@ -551,24 +526,23 @@ mod tests {
let unique_id = 5_u32; let unique_id = 5_u32;
let (req_id, active_req) = reply_testbench.add_tc(TEST_APID, apid_target_id, &[]); let (req_id, active_req) = reply_testbench.add_tc(TEST_APID, apid_target_id, &[]);
let reply = GenericMessage::new( let reply = GenericMessage::new(
req_id.into(), MessageMetadata::new(req_id.into(), sender_id),
sender_id,
HkReply::new(unique_id, HkReplyVariant::Ack), HkReply::new(unique_id, HkReplyVariant::Ack),
); );
let result = reply_testbench.handle_reply(&reply, &active_req, &[]); let result = reply_testbench.handle_reply(&reply, &active_req, &[]);
assert!(result.is_ok()); assert!(result.is_ok());
assert!(result.unwrap()); assert!(result.unwrap());
assert!(reply_testbench reply_testbench
.verif_reporter .verif_reporter
.completion_status(&req_id) .assert_full_completion_success(TEST_COMPONENT_ID.raw(), req_id, None);
.unwrap());
} }
#[test] #[test]
fn reply_handling_unrequested_reply() { fn reply_handling_unrequested_reply() {
let mut testbench = ReplyHandlerTestbench::new(HkReplyHandler::default()); let mut testbench = ReplyHandlerTestbench::new(HkReplyHandler::default());
let action_reply = HkReply::new(5_u32, HkReplyVariant::Ack); let action_reply = HkReply::new(5_u32, HkReplyVariant::Ack);
let unrequested_reply = GenericMessage::new(10_u32, 15_u64, action_reply); let unrequested_reply =
GenericMessage::new(MessageMetadata::new(10_u32, 15_u64), action_reply);
// Right now this function does not do a lot. We simply check that it does not panic or do // Right now this function does not do a lot. We simply check that it does not panic or do
// weird stuff. // weird stuff.
let result = testbench.handle_unrequested_reply(&unrequested_reply); let result = testbench.handle_unrequested_reply(&unrequested_reply);
@ -578,9 +552,14 @@ mod tests {
#[test] #[test]
fn reply_handling_reply_timeout() { fn reply_handling_reply_timeout() {
let mut testbench = ReplyHandlerTestbench::new(HkReplyHandler::default()); let mut testbench = ReplyHandlerTestbench::new(HkReplyHandler::default());
// TODO: Start a request, then time it out with the API and check verification completion let (req_id, active_request) = testbench.add_tc(TEST_APID, TEST_UNIQUE_ID, &[]);
// failure. let result = testbench.handle_request_timeout(&active_request, &[]);
// testbench.reply_handler.handle_request_timeout(active_request, verification_handler, time_stamp, tm_sender) assert!(result.is_ok());
// testbench.default_timeout = Duration::from_millis(50); testbench.verif_reporter.assert_completion_failure(
TEST_COMPONENT_ID.raw(),
req_id,
None,
tmtc_err::REQUEST_TIMEOUT.raw() as u64,
);
} }
} }

View File

@ -2,8 +2,8 @@ use crate::requests::GenericRequestRouter;
use crate::tmtc::MpscStoreAndSendError; use crate::tmtc::MpscStoreAndSendError;
use log::warn; use log::warn;
use satrs::pus::verification::{ use satrs::pus::verification::{
self, FailParams, TcStateAccepted, TcStateStarted, VerificationReportingProvider, self, FailParams, TcStateAccepted, TcStateStarted, VerificationReporter,
VerificationToken, VerificationReporterCfg, VerificationReportingProvider, VerificationToken,
}; };
use satrs::pus::{ use satrs::pus::{
ActiveRequestMapProvider, ActiveRequestProvider, EcssTcAndToken, EcssTcInMemConverter, ActiveRequestMapProvider, ActiveRequestProvider, EcssTcAndToken, EcssTcInMemConverter,
@ -12,13 +12,13 @@ use satrs::pus::{
PusRequestRouter, PusServiceHelper, PusTcToRequestConverter, TcInMemory, PusRequestRouter, PusServiceHelper, PusTcToRequestConverter, TcInMemory,
}; };
use satrs::queue::GenericReceiveError; use satrs::queue::GenericReceiveError;
use satrs::request::GenericMessage; use satrs::request::{Apid, GenericMessage, MessageMetadata};
use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::PusServiceId; use satrs::spacepackets::ecss::PusServiceId;
use satrs::spacepackets::time::cds::TimeProvider;
use satrs::spacepackets::time::TimeWriter;
use satrs::ComponentId; use satrs::ComponentId;
use satrs_example::config::components::PUS_ROUTING_SERVICE;
use satrs_example::config::{tmtc_err, CustomPusServiceId}; use satrs_example::config::{tmtc_err, CustomPusServiceId};
use satrs_example::TimeStampHelper;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::mpsc::{self, Sender}; use std::sync::mpsc::{self, Sender};
@ -30,58 +30,125 @@ pub mod scheduler;
pub mod stack; pub mod stack;
pub mod test; pub mod test;
/// Simple router structure which forwards PUS telecommands to dedicated handlers. pub fn create_verification_reporter(apid: Apid) -> VerificationReporter {
pub struct PusTcMpscRouter { let verif_cfg = VerificationReporterCfg::new(apid, 1, 2, 8).unwrap();
pub test_service_receiver: Sender<EcssTcAndToken>, // Every software component which needs to generate verification telemetry, gets a cloned
pub event_service_receiver: Sender<EcssTcAndToken>, // verification reporter.
pub sched_service_receiver: Sender<EcssTcAndToken>, VerificationReporter::new(&verif_cfg)
pub hk_service_receiver: Sender<EcssTcAndToken>,
pub action_service_receiver: Sender<EcssTcAndToken>,
} }
pub struct PusReceiver<VerificationReporter: VerificationReportingProvider> { /// Simple router structure which forwards PUS telecommands to dedicated handlers.
pub struct PusTcMpscRouter {
pub test_tc_sender: Sender<EcssTcAndToken>,
pub event_tc_sender: Sender<EcssTcAndToken>,
pub sched_tc_sender: Sender<EcssTcAndToken>,
pub hk_tc_sender: Sender<EcssTcAndToken>,
pub action_tc_sender: Sender<EcssTcAndToken>,
pub mode_tc_sender: Sender<EcssTcAndToken>,
}
pub struct PusReceiver<TmSender: EcssTmSenderCore> {
pub id: ComponentId,
pub tm_sender: TmSender,
pub verif_reporter: VerificationReporter, pub verif_reporter: VerificationReporter,
pub pus_router: PusTcMpscRouter, pub pus_router: PusTcMpscRouter,
stamp_helper: TimeStampHelper, stamp_helper: TimeStampHelper,
} }
struct TimeStampHelper { impl<TmSender: EcssTmSenderCore> PusReceiver<TmSender> {
stamper: TimeProvider, pub fn new(tm_sender: TmSender, pus_router: PusTcMpscRouter) -> Self {
time_stamp: [u8; 7],
}
impl TimeStampHelper {
pub fn stamp(&self) -> &[u8] {
&self.time_stamp
}
pub fn update_from_now(&mut self) {
self.stamper
.update_from_now()
.expect("Updating timestamp failed");
self.stamper
.write_to_bytes(&mut self.time_stamp)
.expect("Writing timestamp failed");
}
}
impl Default for TimeStampHelper {
fn default() -> Self {
Self { Self {
stamper: TimeProvider::from_now_with_u16_days().expect("creating time stamper failed"), id: PUS_ROUTING_SERVICE.raw(),
time_stamp: Default::default(), tm_sender,
} verif_reporter: create_verification_reporter(PUS_ROUTING_SERVICE.apid),
}
}
impl<VerificationReporter: VerificationReportingProvider> PusReceiver<VerificationReporter> {
pub fn new(verif_reporter: VerificationReporter, pus_router: PusTcMpscRouter) -> Self {
Self {
verif_reporter,
pus_router, pus_router,
stamp_helper: TimeStampHelper::default(), stamp_helper: TimeStampHelper::default(),
} }
} }
pub fn handle_tc_packet(
&mut self,
tc_in_memory: TcInMemory,
service: u8,
pus_tc: &PusTcReader,
) -> Result<PusPacketHandlerResult, MpscStoreAndSendError> {
let init_token = self.verif_reporter.add_tc(pus_tc);
self.stamp_helper.update_from_now();
let accepted_token = self
.verif_reporter
.acceptance_success(
self.id,
&self.tm_sender,
init_token,
self.stamp_helper.stamp(),
)
.expect("Acceptance success failure");
let service = PusServiceId::try_from(service);
match service {
Ok(standard_service) => match standard_service {
PusServiceId::Test => self.pus_router.test_tc_sender.send(EcssTcAndToken {
tc_in_memory,
token: Some(accepted_token.into()),
})?,
PusServiceId::Housekeeping => {
self.pus_router.hk_tc_sender.send(EcssTcAndToken {
tc_in_memory,
token: Some(accepted_token.into()),
})?
}
PusServiceId::Event => self.pus_router.event_tc_sender.send(EcssTcAndToken {
tc_in_memory,
token: Some(accepted_token.into()),
})?,
PusServiceId::Scheduling => {
self.pus_router.sched_tc_sender.send(EcssTcAndToken {
tc_in_memory,
token: Some(accepted_token.into()),
})?
}
_ => {
let result = self.verif_reporter.start_failure(
self.id,
&self.tm_sender,
accepted_token,
FailParams::new(
self.stamp_helper.stamp(),
&tmtc_err::PUS_SERVICE_NOT_IMPLEMENTED,
&[standard_service as u8],
),
);
if result.is_err() {
warn!("Sending verification failure failed");
}
}
},
Err(e) => {
if let Ok(custom_service) = CustomPusServiceId::try_from(e.number) {
match custom_service {
CustomPusServiceId::Mode => {
// TODO: Fix mode service.
//self.handle_mode_service(pus_tc, accepted_token)
}
CustomPusServiceId::Health => {}
}
} else {
self.verif_reporter
.start_failure(
self.id,
&self.tm_sender,
accepted_token,
FailParams::new(
self.stamp_helper.stamp(),
&tmtc_err::INVALID_PUS_SUBSERVICE,
&[e.number],
),
)
.expect("Start failure verification failed")
}
}
}
Ok(PusPacketHandlerResult::RequestHandled)
}
} }
pub trait TargetedPusService { pub trait TargetedPusService {
@ -123,7 +190,6 @@ pub struct PusTargetedRequestService<
RequestType, RequestType,
ReplyType, ReplyType,
> { > {
pub id: ComponentId,
pub service_helper: pub service_helper:
PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>, PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
pub request_router: GenericRequestRouter, pub request_router: GenericRequestRouter,
@ -162,7 +228,6 @@ where
GenericRequestRouter: PusRequestRouter<RequestType, Error = GenericRoutingError>, GenericRequestRouter: PusRequestRouter<RequestType, Error = GenericRoutingError>,
{ {
pub fn new( pub fn new(
id: ComponentId,
service_helper: PusServiceHelper< service_helper: PusServiceHelper<
TcReceiver, TcReceiver,
TmSender, TmSender,
@ -176,7 +241,6 @@ where
reply_receiver: mpsc::Receiver<GenericMessage<ReplyType>>, reply_receiver: mpsc::Receiver<GenericMessage<ReplyType>>,
) -> Self { ) -> Self {
Self { Self {
id,
service_helper, service_helper,
request_converter, request_converter,
active_request_map, active_request_map,
@ -201,10 +265,12 @@ where
.cache(&ecss_tc_and_token.tc_in_memory)?; .cache(&ecss_tc_and_token.tc_in_memory)?;
let tc = self.service_helper.tc_in_mem_converter().convert()?; let tc = self.service_helper.tc_in_mem_converter().convert()?;
let (mut request_info, request) = match self.request_converter.convert( let (mut request_info, request) = match self.request_converter.convert(
self.service_helper.id(),
ecss_tc_and_token.token, ecss_tc_and_token.token,
&tc, &tc,
time_stamp, self.service_helper.tm_sender(),
&self.service_helper.common.verif_reporter, &self.service_helper.common.verif_reporter,
time_stamp,
) { ) {
Ok((info, req)) => (info, req), Ok((info, req)) => (info, req),
Err(e) => { Err(e) => {
@ -218,8 +284,7 @@ where
.expect("token not in expected accepted state"); .expect("token not in expected accepted state");
let verif_request_id = verification::RequestId::new(&tc).raw(); let verif_request_id = verification::RequestId::new(&tc).raw();
match self.request_router.route( match self.request_router.route(
verif_request_id, MessageMetadata::new(verif_request_id, self.service_helper.id()),
self.id,
request_info.target_id(), request_info.target_id(),
request, request,
) { ) {
@ -227,7 +292,12 @@ where
let started_token = self let started_token = self
.service_helper .service_helper
.verif_reporter() .verif_reporter()
.start_success(accepted_token, time_stamp) .start_success(
self.service_helper.id(),
&self.service_helper.common.tm_sender,
accepted_token,
time_stamp,
)
.expect("Start success failure"); .expect("Start success failure");
request_info.set_token(started_token.into()); request_info.set_token(started_token.into());
self.active_request_map self.active_request_map
@ -238,8 +308,9 @@ where
&request_info, &request_info,
&tc, &tc,
e.clone(), e.clone(),
time_stamp, self.service_helper.tm_sender(),
self.service_helper.verif_reporter(), self.service_helper.verif_reporter(),
time_stamp,
); );
return Err(e.into()); return Err(e.into());
} }
@ -259,6 +330,8 @@ where
self.service_helper self.service_helper
.verif_reporter() .verif_reporter()
.completion_failure( .completion_failure(
self.service_helper.id(),
self.service_helper.tm_sender(),
token, token,
FailParams::new(time_stamp, &tmtc_err::INVALID_PUS_SERVICE, &service_slice), FailParams::new(time_stamp, &tmtc_err::INVALID_PUS_SERVICE, &service_slice),
) )
@ -269,6 +342,8 @@ where
self.service_helper self.service_helper
.verif_reporter() .verif_reporter()
.completion_failure( .completion_failure(
self.service_helper.id(),
self.service_helper.tm_sender(),
token, token,
FailParams::new( FailParams::new(
time_stamp, time_stamp,
@ -284,6 +359,8 @@ where
self.service_helper self.service_helper
.verif_reporter() .verif_reporter()
.completion_failure( .completion_failure(
self.service_helper.id(),
self.service_helper.tm_sender(),
token, token,
FailParams::new(time_stamp, &tmtc_err::NOT_ENOUGH_APP_DATA, &context_info), FailParams::new(time_stamp, &tmtc_err::NOT_ENOUGH_APP_DATA, &context_info),
) )
@ -314,25 +391,29 @@ where
reply: &GenericMessage<ReplyType>, reply: &GenericMessage<ReplyType>,
time_stamp: &[u8], time_stamp: &[u8],
) -> Result<(), EcssTmtcError> { ) -> Result<(), EcssTmtcError> {
let active_req_opt = self.active_request_map.get(reply.request_id); let active_req_opt = self.active_request_map.get(reply.request_id());
if active_req_opt.is_none() { if active_req_opt.is_none() {
self.reply_handler self.reply_handler.handle_unrequested_reply(
.handle_unrequested_reply(reply, &self.service_helper.common.tm_sender)?; self.service_helper.id(),
reply,
&self.service_helper.common.tm_sender,
)?;
return Ok(()); return Ok(());
} }
let active_request = active_req_opt.unwrap(); let active_request = active_req_opt.unwrap();
let request_finished = self let request_finished = self
.reply_handler .reply_handler
.handle_reply( .handle_reply(
self.service_helper.id(),
reply, reply,
active_request, active_request,
&self.service_helper.common.tm_sender,
&self.service_helper.common.verif_reporter, &self.service_helper.common.verif_reporter,
time_stamp, time_stamp,
&self.service_helper.common.tm_sender,
) )
.unwrap_or(false); .unwrap_or(false);
if request_finished { if request_finished {
self.active_request_map.remove(reply.request_id); self.active_request_map.remove(reply.request_id());
} }
Ok(()) Ok(())
} }
@ -356,6 +437,8 @@ where
/// Generic timeout handling: Handle the verification failure with a dedicated return code /// Generic timeout handling: Handle the verification failure with a dedicated return code
/// and also log the error. /// and also log the error.
pub fn generic_pus_request_timeout_handler( pub fn generic_pus_request_timeout_handler(
sender_id: ComponentId,
sender: &(impl EcssTmSenderCore + ?Sized),
active_request: &(impl ActiveRequestProvider + Debug), active_request: &(impl ActiveRequestProvider + Debug),
verification_handler: &impl VerificationReportingProvider, verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8], time_stamp: &[u8],
@ -366,118 +449,27 @@ pub fn generic_pus_request_timeout_handler(
.token() .token()
.try_into() .try_into()
.expect("token not in expected started state"); .expect("token not in expected started state");
verification_handler verification_handler.completion_failure(
.completion_failure( sender_id,
started_token, sender,
FailParams::new( started_token,
time_stamp, FailParams::new(time_stamp, &tmtc_err::REQUEST_TIMEOUT, &[]),
&satrs_example::config::tmtc_err::REQUEST_TIMEOUT, )?;
&[],
),
)
.map_err(|e| e.0)?;
Ok(()) Ok(())
} }
impl<VerificationReporter: VerificationReportingProvider> PusReceiver<VerificationReporter> {
pub fn handle_tc_packet(
&mut self,
tc_in_memory: TcInMemory,
service: u8,
pus_tc: &PusTcReader,
) -> Result<PusPacketHandlerResult, MpscStoreAndSendError> {
let init_token = self.verif_reporter.add_tc(pus_tc);
self.stamp_helper.update_from_now();
let accepted_token = self
.verif_reporter
.acceptance_success(init_token, self.stamp_helper.stamp())
.expect("Acceptance success failure");
let service = PusServiceId::try_from(service);
match service {
Ok(standard_service) => match standard_service {
PusServiceId::Test => {
self.pus_router.test_service_receiver.send(EcssTcAndToken {
tc_in_memory,
token: Some(accepted_token.into()),
})?
}
PusServiceId::Housekeeping => {
self.pus_router.hk_service_receiver.send(EcssTcAndToken {
tc_in_memory,
token: Some(accepted_token.into()),
})?
}
PusServiceId::Event => {
self.pus_router
.event_service_receiver
.send(EcssTcAndToken {
tc_in_memory,
token: Some(accepted_token.into()),
})?
}
PusServiceId::Scheduling => {
self.pus_router
.sched_service_receiver
.send(EcssTcAndToken {
tc_in_memory,
token: Some(accepted_token.into()),
})?
}
_ => {
let result = self.verif_reporter.start_failure(
accepted_token,
FailParams::new(
self.stamp_helper.stamp(),
&tmtc_err::PUS_SERVICE_NOT_IMPLEMENTED,
&[standard_service as u8],
),
);
if result.is_err() {
warn!("Sending verification failure failed");
}
}
},
Err(e) => {
if let Ok(custom_service) = CustomPusServiceId::try_from(e.number) {
match custom_service {
CustomPusServiceId::Mode => {
// TODO: Fix mode service.
//self.handle_mode_service(pus_tc, accepted_token)
}
CustomPusServiceId::Health => {}
}
} else {
self.verif_reporter
.start_failure(
accepted_token,
FailParams::new(
self.stamp_helper.stamp(),
&tmtc_err::INVALID_PUS_SUBSERVICE,
&[e.number],
),
)
.expect("Start failure verification failed")
}
}
}
Ok(PusPacketHandlerResult::RequestHandled)
}
}
#[cfg(test)] #[cfg(test)]
pub(crate) mod tests { pub(crate) mod tests {
use std::time::Duration; use std::time::Duration;
use satrs::pus::test_util::TEST_COMPONENT_ID;
use satrs::pus::{MpscTmAsVecSender, PusTmAsVec, PusTmVariant};
use satrs::{ use satrs::{
pus::{ pus::{
verification::{ verification::test_util::TestVerificationReporter, ActivePusRequestStd,
test_util::{SharedVerificationMap, TestVerificationReporter}, ActiveRequestMapProvider, EcssTcInVecConverter, MpscTcReceiver,
VerificationReporterWithVecMpscSender,
},
ActivePusRequestStd, ActiveRequestMapProvider, EcssTcInVecConverter, MpscTcReceiver,
TmAsVecSenderWithMpsc,
}, },
request::TargetAndApidId, request::UniqueApidTargetId,
spacepackets::{ spacepackets::{
ecss::{ ecss::{
tc::{PusTcCreator, PusTcSecondaryHeader}, tc::{PusTcCreator, PusTcSecondaryHeader},
@ -491,22 +483,18 @@ pub(crate) mod tests {
use super::*; use super::*;
pub const TEST_APID: u16 = 0x23;
pub const TEST_APID_TARGET_ID: u32 = 5;
pub const TARGET_ID: TargetAndApidId = TargetAndApidId::new(TEST_APID, TEST_APID_TARGET_ID);
// Testbench dedicated to the testing of [PusReplyHandler]s // Testbench dedicated to the testing of [PusReplyHandler]s
pub struct ReplyHandlerTestbench< pub struct ReplyHandlerTestbench<
ReplyHandler: PusReplyHandler<ActiveRequestInfo, Reply, Error = EcssTmtcError>, ReplyHandler: PusReplyHandler<ActiveRequestInfo, Reply, Error = EcssTmtcError>,
ActiveRequestInfo: ActiveRequestProvider, ActiveRequestInfo: ActiveRequestProvider,
Reply, Reply,
> { > {
pub shared_verif_map: SharedVerificationMap, pub id: ComponentId,
pub verif_reporter: TestVerificationReporter, pub verif_reporter: TestVerificationReporter,
pub reply_handler: ReplyHandler, pub reply_handler: ReplyHandler,
pub tm_receiver: mpsc::Receiver<Vec<u8>>, pub tm_receiver: mpsc::Receiver<PusTmAsVec>,
pub default_timeout: Duration, pub default_timeout: Duration,
tm_sender: TmAsVecSenderWithMpsc, tm_sender: MpscTmAsVecSender,
phantom: std::marker::PhantomData<(ActiveRequestInfo, Reply)>, phantom: std::marker::PhantomData<(ActiveRequestInfo, Reply)>,
} }
@ -517,15 +505,14 @@ pub(crate) mod tests {
> ReplyHandlerTestbench<ReplyHandler, ActiveRequestInfo, Reply> > ReplyHandlerTestbench<ReplyHandler, ActiveRequestInfo, Reply>
{ {
pub fn new(reply_handler: ReplyHandler) -> Self { pub fn new(reply_handler: ReplyHandler) -> Self {
let shared_verif_map = SharedVerificationMap::default(); let test_verif_reporter = TestVerificationReporter::default();
let test_verif_reporter = TestVerificationReporter::new(shared_verif_map.clone());
let (tm_sender, tm_receiver) = mpsc::channel(); let (tm_sender, tm_receiver) = mpsc::channel();
Self { Self {
shared_verif_map, id: TEST_COMPONENT_ID.raw(),
verif_reporter: test_verif_reporter, verif_reporter: test_verif_reporter,
reply_handler, reply_handler,
default_timeout: Duration::from_secs(30), default_timeout: Duration::from_secs(30),
tm_sender: TmAsVecSenderWithMpsc::new(0, "TEST_SENDER", tm_sender), tm_sender,
tm_receiver, tm_receiver,
phantom: std::marker::PhantomData, phantom: std::marker::PhantomData,
} }
@ -547,16 +534,16 @@ pub(crate) mod tests {
)); ));
let accepted = self let accepted = self
.verif_reporter .verif_reporter
.acceptance_success(init, time_stamp) .acceptance_success(self.id, &self.tm_sender, init, time_stamp)
.expect("acceptance failed"); .expect("acceptance failed");
let started = self let started = self
.verif_reporter .verif_reporter
.start_success(accepted, time_stamp) .start_success(self.id, &self.tm_sender, accepted, time_stamp)
.expect("start failed"); .expect("start failed");
( (
started.request_id(), started.request_id(),
ActivePusRequestStd::new( ActivePusRequestStd::new(
TargetAndApidId::new(apid, apid_target).raw(), UniqueApidTargetId::new(apid, apid_target).raw(),
started, started,
self.default_timeout, self.default_timeout,
), ),
@ -570,11 +557,12 @@ pub(crate) mod tests {
time_stamp: &[u8], time_stamp: &[u8],
) -> Result<bool, ReplyHandler::Error> { ) -> Result<bool, ReplyHandler::Error> {
self.reply_handler.handle_reply( self.reply_handler.handle_reply(
self.id,
reply, reply,
active_request, active_request,
&self.tm_sender,
&self.verif_reporter, &self.verif_reporter,
time_stamp, time_stamp,
&self.tm_sender,
) )
} }
@ -583,7 +571,32 @@ pub(crate) mod tests {
reply: &GenericMessage<Reply>, reply: &GenericMessage<Reply>,
) -> Result<(), ReplyHandler::Error> { ) -> Result<(), ReplyHandler::Error> {
self.reply_handler self.reply_handler
.handle_unrequested_reply(reply, &self.tm_sender) .handle_unrequested_reply(self.id, reply, &self.tm_sender)
}
pub fn handle_request_timeout(
&mut self,
active_request_info: &ActiveRequestInfo,
time_stamp: &[u8],
) -> Result<(), ReplyHandler::Error> {
self.reply_handler.handle_request_timeout(
self.id,
active_request_info,
&self.tm_sender,
&self.verif_reporter,
time_stamp,
)
}
}
#[derive(Default)]
pub struct DummySender {}
/// Dummy sender component which does nothing on the [Self::send_tm] call.
///
/// Useful for unit tests.
impl EcssTmSenderCore for DummySender {
fn send_tm(&self, _source_id: ComponentId, _tm: PusTmVariant) -> Result<(), EcssTmtcError> {
Ok(())
} }
} }
@ -593,9 +606,10 @@ pub(crate) mod tests {
ActiveRequestInfo: ActiveRequestProvider, ActiveRequestInfo: ActiveRequestProvider,
Request, Request,
> { > {
pub shared_verif_map: SharedVerificationMap, pub id: ComponentId,
pub verif_reporter: TestVerificationReporter, pub verif_reporter: TestVerificationReporter,
pub converter: Converter, pub converter: Converter,
dummy_sender: DummySender,
current_request_id: Option<verification::RequestId>, current_request_id: Option<verification::RequestId>,
current_packet: Option<Vec<u8>>, current_packet: Option<Vec<u8>>,
phantom: std::marker::PhantomData<(ActiveRequestInfo, Request)>, phantom: std::marker::PhantomData<(ActiveRequestInfo, Request)>,
@ -608,12 +622,12 @@ pub(crate) mod tests {
> PusConverterTestbench<Converter, ActiveRequestInfo, Request> > PusConverterTestbench<Converter, ActiveRequestInfo, Request>
{ {
pub fn new(converter: Converter) -> Self { pub fn new(converter: Converter) -> Self {
let shared_verif_map = SharedVerificationMap::default(); let test_verif_reporter = TestVerificationReporter::default();
let test_verif_reporter = TestVerificationReporter::new(shared_verif_map.clone());
Self { Self {
shared_verif_map, id: TEST_COMPONENT_ID.raw(),
verif_reporter: test_verif_reporter, verif_reporter: test_verif_reporter,
converter, converter,
dummy_sender: DummySender::default(),
current_request_id: None, current_request_id: None,
current_packet: None, current_packet: None,
phantom: std::marker::PhantomData, phantom: std::marker::PhantomData,
@ -625,7 +639,7 @@ pub(crate) mod tests {
self.current_request_id = Some(verification::RequestId::new(tc)); self.current_request_id = Some(verification::RequestId::new(tc));
self.current_packet = Some(tc.to_vec().unwrap()); self.current_packet = Some(tc.to_vec().unwrap());
self.verif_reporter self.verif_reporter
.acceptance_success(token, &[]) .acceptance_success(self.id, &self.dummy_sender, token, &[])
.expect("acceptance failed") .expect("acceptance failed")
} }
@ -647,16 +661,21 @@ pub(crate) mod tests {
} }
let current_packet = self.current_packet.take().unwrap(); let current_packet = self.current_packet.take().unwrap();
let tc_reader = PusTcReader::new(&current_packet).unwrap(); let tc_reader = PusTcReader::new(&current_packet).unwrap();
let (active_info, request) = let (active_info, request) = self.converter.convert(
self.converter self.id,
.convert(token, &tc_reader.0, time_stamp, &self.verif_reporter)?; token,
&tc_reader.0,
&self.dummy_sender,
&self.verif_reporter,
time_stamp,
)?;
assert_eq!( assert_eq!(
active_info.token().request_id(), active_info.token().request_id(),
self.request_id().expect("no request id is set") self.request_id().expect("no request id is set")
); );
assert_eq!( assert_eq!(
active_info.target_id(), active_info.target_id(),
TargetAndApidId::new(expected_apid, expected_apid_target).raw() UniqueApidTargetId::new(expected_apid, expected_apid_target).raw()
); );
Ok((active_info, request)) Ok((active_info, request))
} }
@ -672,9 +691,9 @@ pub(crate) mod tests {
> { > {
pub service: PusTargetedRequestService< pub service: PusTargetedRequestService<
MpscTcReceiver, MpscTcReceiver,
TmAsVecSenderWithMpsc, MpscTmAsVecSender,
EcssTcInVecConverter, EcssTcInVecConverter,
VerificationReporterWithVecMpscSender, TestVerificationReporter,
RequestConverter, RequestConverter,
ReplyHandler, ReplyHandler,
ActiveRequestMap, ActiveRequestMap,
@ -682,8 +701,7 @@ pub(crate) mod tests {
RequestType, RequestType,
ReplyType, ReplyType,
>, >,
pub verif_reporter: VerificationReporterWithVecMpscSender, pub tm_funnel_rx: mpsc::Receiver<PusTmAsVec>,
pub tm_funnel_rx: mpsc::Receiver<Vec<u8>>,
pub pus_packet_tx: mpsc::Sender<EcssTcAndToken>, pub pus_packet_tx: mpsc::Sender<EcssTcAndToken>,
pub reply_tx: mpsc::Sender<GenericMessage<ReplyType>>, pub reply_tx: mpsc::Sender<GenericMessage<ReplyType>>,
pub request_rx: mpsc::Receiver<GenericMessage<CompositeRequest>>, pub request_rx: mpsc::Receiver<GenericMessage<CompositeRequest>>,

View File

@ -1,5 +1,16 @@
use log::{error, warn};
use std::sync::mpsc;
use std::time::Duration; use std::time::Duration;
use crate::requests::GenericRequestRouter;
use satrs::pool::SharedStaticMemoryPool;
use satrs::pus::verification::VerificationReporter;
use satrs::pus::{
DefaultActiveRequestMap, EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter,
EcssTcInVecConverter, MpscTcReceiver, MpscTmAsVecSender, MpscTmInSharedPoolSenderBounded,
PusPacketHandlerResult, PusServiceHelper, PusTmAsVec, PusTmInPool, TmInSharedPoolSender,
};
use satrs::request::GenericMessage;
use satrs::{ use satrs::{
mode::{ModeAndSubmode, ModeReply, ModeRequest}, mode::{ModeAndSubmode, ModeReply, ModeRequest},
pus::{ pus::{
@ -9,9 +20,9 @@ use satrs::{
VerificationToken, VerificationToken,
}, },
ActivePusRequestStd, ActiveRequestProvider, EcssTmSenderCore, EcssTmtcError, ActivePusRequestStd, ActiveRequestProvider, EcssTmSenderCore, EcssTmtcError,
GenericConversionError, PusReplyHandler, PusTcToRequestConverter, PusTmWrapper, GenericConversionError, PusReplyHandler, PusTcToRequestConverter, PusTmVariant,
}, },
request::TargetAndApidId, request::UniqueApidTargetId,
spacepackets::{ spacepackets::{
ecss::{ ecss::{
tc::PusTcReader, tc::PusTcReader,
@ -20,10 +31,15 @@ use satrs::{
}, },
SpHeader, SpHeader,
}, },
ComponentId,
}; };
use satrs_example::config::components::PUS_MODE_SERVICE;
use satrs_example::config::{mode_err, tmtc_err}; use satrs_example::config::{mode_err, tmtc_err};
use super::generic_pus_request_timeout_handler; use super::{
create_verification_reporter, generic_pus_request_timeout_handler, PusTargetedRequestService,
TargetedPusService,
};
#[derive(Default)] #[derive(Default)]
pub struct ModeReplyHandler {} pub struct ModeReplyHandler {}
@ -33,7 +49,8 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
fn handle_unrequested_reply( fn handle_unrequested_reply(
&mut self, &mut self,
reply: &satrs::request::GenericMessage<ModeReply>, _caller_id: ComponentId,
reply: &GenericMessage<ModeReply>,
_tm_sender: &impl EcssTmSenderCore, _tm_sender: &impl EcssTmSenderCore,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
log::warn!("received unexpected reply for mode service 5: {reply:?}"); log::warn!("received unexpected reply for mode service 5: {reply:?}");
@ -42,30 +59,24 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
fn handle_reply( fn handle_reply(
&mut self, &mut self,
reply: &satrs::request::GenericMessage<ModeReply>, caller_id: ComponentId,
reply: &GenericMessage<ModeReply>,
active_request: &ActivePusRequestStd, active_request: &ActivePusRequestStd,
tm_sender: &impl EcssTmSenderCore,
verification_handler: &impl VerificationReportingProvider, verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8], time_stamp: &[u8],
tm_sender: &impl EcssTmSenderCore,
) -> Result<bool, Self::Error> { ) -> Result<bool, Self::Error> {
let started_token: VerificationToken<TcStateStarted> = active_request let started_token: VerificationToken<TcStateStarted> = active_request
.token() .token()
.try_into() .try_into()
.expect("invalid token state"); .expect("invalid token state");
match reply.message { match reply.message {
ModeReply::ModeInfo(info) => {
log::warn!(
"received unrequest mode information for active request {:?}: {:?}",
active_request,
info
);
}
ModeReply::ModeReply(mode_reply) => { ModeReply::ModeReply(mode_reply) => {
let mut source_data: [u8; 12] = [0; 12]; let mut source_data: [u8; 12] = [0; 12];
mode_reply mode_reply
.write_to_be_bytes(&mut source_data) .write_to_be_bytes(&mut source_data)
.expect("writing mode reply failed"); .expect("writing mode reply failed");
let req_id = verification::RequestId::from(reply.request_id); let req_id = verification::RequestId::from(reply.request_id());
let mut sp_header = SpHeader::tm_unseg(req_id.packet_id().apid(), 0, 0) let mut sp_header = SpHeader::tm_unseg(req_id.packet_id().apid(), 0, 0)
.expect("generating SP header failed"); .expect("generating SP header failed");
let sec_header = PusTmSecondaryHeader::new( let sec_header = PusTmSecondaryHeader::new(
@ -76,18 +87,21 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
Some(time_stamp), Some(time_stamp),
); );
let pus_tm = PusTmCreator::new(&mut sp_header, sec_header, &source_data, true); let pus_tm = PusTmCreator::new(&mut sp_header, sec_header, &source_data, true);
tm_sender.send_tm(PusTmWrapper::Direct(pus_tm))?; tm_sender.send_tm(caller_id, PusTmVariant::Direct(pus_tm))?;
verification_handler verification_handler.completion_success(
.completion_success(started_token, time_stamp) caller_id,
.map_err(|e| e.0)?; tm_sender,
started_token,
time_stamp,
)?;
} }
ModeReply::CantReachMode(error_code) => { ModeReply::CantReachMode(error_code) => {
verification_handler verification_handler.completion_failure(
.completion_failure( caller_id,
started_token, tm_sender,
FailParams::new(time_stamp, &error_code, &[]), started_token,
) FailParams::new(time_stamp, &error_code, &[]),
.map_err(|e| e.0)?; )?;
} }
ModeReply::WrongMode { expected, reached } => { ModeReply::WrongMode { expected, reached } => {
let mut error_info: [u8; 24] = [0; 24]; let mut error_info: [u8; 24] = [0; 24];
@ -97,16 +111,16 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
written_len += reached written_len += reached
.write_to_be_bytes(&mut error_info[ModeAndSubmode::RAW_LEN..]) .write_to_be_bytes(&mut error_info[ModeAndSubmode::RAW_LEN..])
.expect("writing reached mode failed"); .expect("writing reached mode failed");
verification_handler verification_handler.completion_failure(
.completion_failure( caller_id,
started_token, tm_sender,
FailParams::new( started_token,
time_stamp, FailParams::new(
&mode_err::WRONG_MODE, time_stamp,
&error_info[..written_len], &mode_err::WRONG_MODE,
), &error_info[..written_len],
) ),
.map_err(|e| e.0)?; )?;
} }
}; };
Ok(true) Ok(true)
@ -114,12 +128,15 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
fn handle_request_timeout( fn handle_request_timeout(
&mut self, &mut self,
caller_id: ComponentId,
active_request: &ActivePusRequestStd, active_request: &ActivePusRequestStd,
tm_sender: &impl EcssTmSenderCore,
verification_handler: &impl VerificationReportingProvider, verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8], time_stamp: &[u8],
_tm_sender: &impl EcssTmSenderCore,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
generic_pus_request_timeout_handler( generic_pus_request_timeout_handler(
caller_id,
tm_sender,
active_request, active_request,
verification_handler, verification_handler,
time_stamp, time_stamp,
@ -137,16 +154,21 @@ impl PusTcToRequestConverter<ActivePusRequestStd, ModeRequest> for ModeRequestCo
fn convert( fn convert(
&mut self, &mut self,
caller_id: ComponentId,
token: VerificationToken<TcStateAccepted>, token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader, tc: &PusTcReader,
time_stamp: &[u8], tm_sender: &(impl EcssTmSenderCore + ?Sized),
verif_reporter: &impl VerificationReportingProvider, verif_reporter: &impl VerificationReportingProvider,
time_stamp: &[u8],
) -> Result<(ActivePusRequestStd, ModeRequest), Self::Error> { ) -> Result<(ActivePusRequestStd, ModeRequest), Self::Error> {
let subservice = tc.subservice(); let subservice = tc.subservice();
let user_data = tc.user_data(); let user_data = tc.user_data();
let not_enough_app_data = |expected: usize| { let not_enough_app_data = |expected: usize| {
verif_reporter verif_reporter
.start_failure( .start_failure(
caller_id,
tm_sender,
token, token,
FailParams::new_no_fail_data(time_stamp, &tmtc_err::NOT_ENOUGH_APP_DATA), FailParams::new_no_fail_data(time_stamp, &tmtc_err::NOT_ENOUGH_APP_DATA),
) )
@ -159,7 +181,7 @@ impl PusTcToRequestConverter<ActivePusRequestStd, ModeRequest> for ModeRequestCo
if user_data.len() < core::mem::size_of::<u32>() { if user_data.len() < core::mem::size_of::<u32>() {
return not_enough_app_data(4); return not_enough_app_data(4);
} }
let target_id_and_apid = TargetAndApidId::from_pus_tc(tc).unwrap(); let target_id_and_apid = UniqueApidTargetId::from_pus_tc(tc).unwrap();
let active_request = let active_request =
ActivePusRequestStd::new(target_id_and_apid.into(), token, Duration::from_secs(30)); ActivePusRequestStd::new(target_id_and_apid.into(), token, Duration::from_secs(30));
let subservice_typed = Subservice::try_from(subservice); let subservice_typed = Subservice::try_from(subservice);
@ -167,6 +189,8 @@ impl PusTcToRequestConverter<ActivePusRequestStd, ModeRequest> for ModeRequestCo
// Invalid subservice // Invalid subservice
verif_reporter verif_reporter
.start_failure( .start_failure(
caller_id,
tm_sender,
token, token,
FailParams::new_no_fail_data(time_stamp, &tmtc_err::INVALID_PUS_SUBSERVICE), FailParams::new_no_fail_data(time_stamp, &tmtc_err::INVALID_PUS_SUBSERVICE),
) )
@ -196,8 +220,117 @@ impl PusTcToRequestConverter<ActivePusRequestStd, ModeRequest> for ModeRequestCo
} }
} }
pub fn create_mode_service_static(
tm_sender: TmInSharedPoolSender<mpsc::SyncSender<PusTmInPool>>,
tc_pool: SharedStaticMemoryPool,
pus_action_rx: mpsc::Receiver<EcssTcAndToken>,
mode_router: GenericRequestRouter,
reply_receiver: mpsc::Receiver<GenericMessage<ModeReply>>,
) -> ModeServiceWrapper<MpscTmInSharedPoolSenderBounded, EcssTcInSharedStoreConverter> {
let mode_request_handler = PusTargetedRequestService::new(
PusServiceHelper::new(
PUS_MODE_SERVICE.raw(),
pus_action_rx,
tm_sender,
create_verification_reporter(PUS_MODE_SERVICE.apid),
EcssTcInSharedStoreConverter::new(tc_pool, 2048),
),
ModeRequestConverter::default(),
DefaultActiveRequestMap::default(),
ModeReplyHandler::default(),
mode_router,
reply_receiver,
);
ModeServiceWrapper {
service: mode_request_handler,
}
}
pub fn create_mode_service_dynamic(
tm_funnel_tx: mpsc::Sender<PusTmAsVec>,
pus_action_rx: mpsc::Receiver<EcssTcAndToken>,
mode_router: GenericRequestRouter,
reply_receiver: mpsc::Receiver<GenericMessage<ModeReply>>,
) -> ModeServiceWrapper<MpscTmAsVecSender, EcssTcInVecConverter> {
let mode_request_handler = PusTargetedRequestService::new(
PusServiceHelper::new(
PUS_MODE_SERVICE.raw(),
pus_action_rx,
tm_funnel_tx,
create_verification_reporter(PUS_MODE_SERVICE.apid),
EcssTcInVecConverter::default(),
),
ModeRequestConverter::default(),
DefaultActiveRequestMap::default(),
ModeReplyHandler::default(),
mode_router,
reply_receiver,
);
ModeServiceWrapper {
service: mode_request_handler,
}
}
pub struct ModeServiceWrapper<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter> {
pub(crate) service: PusTargetedRequestService<
MpscTcReceiver,
TmSender,
TcInMemConverter,
VerificationReporter,
ModeRequestConverter,
ModeReplyHandler,
DefaultActiveRequestMap<ActivePusRequestStd>,
ActivePusRequestStd,
ModeRequest,
ModeReply,
>,
}
impl<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter> TargetedPusService
for ModeServiceWrapper<TmSender, TcInMemConverter>
{
/// Returns [true] if the packet handling is finished.
fn poll_and_handle_next_tc(&mut self, time_stamp: &[u8]) -> bool {
match self.service.poll_and_handle_next_tc(time_stamp) {
Ok(result) => match result {
PusPacketHandlerResult::RequestHandled => {}
PusPacketHandlerResult::RequestHandledPartialSuccess(e) => {
warn!("PUS mode service: partial packet handling success: {e:?}")
}
PusPacketHandlerResult::CustomSubservice(invalid, _) => {
warn!("PUS mode service: invalid subservice {invalid}");
}
PusPacketHandlerResult::SubserviceNotImplemented(subservice, _) => {
warn!("PUS mode service: {subservice} not implemented");
}
PusPacketHandlerResult::Empty => {
return true;
}
},
Err(error) => {
error!("PUS mode service: packet handling error: {error:?}")
}
}
false
}
fn poll_and_handle_next_reply(&mut self, time_stamp: &[u8]) -> bool {
self.service
.poll_and_check_next_reply(time_stamp)
.unwrap_or_else(|e| {
warn!("PUS action service: Handling reply failed with error {e:?}");
false
})
}
fn check_for_request_timeouts(&mut self) {
self.service.check_for_request_timeouts();
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use satrs::pus::test_util::{TEST_APID, TEST_COMPONENT_ID, TEST_UNIQUE_ID};
use satrs::request::MessageMetadata;
use satrs::{ use satrs::{
mode::{ModeAndSubmode, ModeReply, ModeRequest}, mode::{ModeAndSubmode, ModeReply, ModeRequest},
pus::mode::Subservice, pus::mode::Subservice,
@ -207,10 +340,11 @@ mod tests {
SpHeader, SpHeader,
}, },
}; };
use satrs_example::config::tmtc_err;
use crate::pus::{ use crate::pus::{
mode::ModeReplyHandler, mode::ModeReplyHandler,
tests::{PusConverterTestbench, ReplyHandlerTestbench, TEST_APID, TEST_APID_TARGET_ID}, tests::{PusConverterTestbench, ReplyHandlerTestbench},
}; };
use super::ModeRequestConverter; use super::ModeRequestConverter;
@ -221,11 +355,11 @@ mod tests {
let mut sp_header = SpHeader::tc_unseg(TEST_APID, 0, 0).unwrap(); let mut sp_header = SpHeader::tc_unseg(TEST_APID, 0, 0).unwrap();
let sec_header = PusTcSecondaryHeader::new_simple(200, Subservice::TcReadMode as u8); let sec_header = PusTcSecondaryHeader::new_simple(200, Subservice::TcReadMode as u8);
let mut app_data: [u8; 4] = [0; 4]; let mut app_data: [u8; 4] = [0; 4];
app_data[0..4].copy_from_slice(&TEST_APID_TARGET_ID.to_be_bytes()); app_data[0..4].copy_from_slice(&TEST_UNIQUE_ID.to_be_bytes());
let tc = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true); let tc = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true);
let token = testbench.add_tc(&tc); let token = testbench.add_tc(&tc);
let (_active_req, req) = testbench let (_active_req, req) = testbench
.convert(token, &[], TEST_APID, TEST_APID_TARGET_ID) .convert(token, &[], TEST_APID, TEST_UNIQUE_ID)
.expect("conversion has failed"); .expect("conversion has failed");
assert_eq!(req, ModeRequest::ReadMode); assert_eq!(req, ModeRequest::ReadMode);
} }
@ -237,14 +371,14 @@ mod tests {
let sec_header = PusTcSecondaryHeader::new_simple(200, Subservice::TcSetMode as u8); let sec_header = PusTcSecondaryHeader::new_simple(200, Subservice::TcSetMode as u8);
let mut app_data: [u8; 4 + ModeAndSubmode::RAW_LEN] = [0; 4 + ModeAndSubmode::RAW_LEN]; let mut app_data: [u8; 4 + ModeAndSubmode::RAW_LEN] = [0; 4 + ModeAndSubmode::RAW_LEN];
let mode_and_submode = ModeAndSubmode::new(2, 1); let mode_and_submode = ModeAndSubmode::new(2, 1);
app_data[0..4].copy_from_slice(&TEST_APID_TARGET_ID.to_be_bytes()); app_data[0..4].copy_from_slice(&TEST_UNIQUE_ID.to_be_bytes());
mode_and_submode mode_and_submode
.write_to_be_bytes(&mut app_data[4..]) .write_to_be_bytes(&mut app_data[4..])
.unwrap(); .unwrap();
let tc = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true); let tc = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true);
let token = testbench.add_tc(&tc); let token = testbench.add_tc(&tc);
let (_active_req, req) = testbench let (_active_req, req) = testbench
.convert(token, &[], TEST_APID, TEST_APID_TARGET_ID) .convert(token, &[], TEST_APID, TEST_UNIQUE_ID)
.expect("conversion has failed"); .expect("conversion has failed");
assert_eq!(req, ModeRequest::SetMode(mode_and_submode)); assert_eq!(req, ModeRequest::SetMode(mode_and_submode));
} }
@ -255,11 +389,11 @@ mod tests {
let mut sp_header = SpHeader::tc_unseg(TEST_APID, 0, 0).unwrap(); let mut sp_header = SpHeader::tc_unseg(TEST_APID, 0, 0).unwrap();
let sec_header = PusTcSecondaryHeader::new_simple(200, Subservice::TcAnnounceMode as u8); let sec_header = PusTcSecondaryHeader::new_simple(200, Subservice::TcAnnounceMode as u8);
let mut app_data: [u8; 4] = [0; 4]; let mut app_data: [u8; 4] = [0; 4];
app_data[0..4].copy_from_slice(&TEST_APID_TARGET_ID.to_be_bytes()); app_data[0..4].copy_from_slice(&TEST_UNIQUE_ID.to_be_bytes());
let tc = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true); let tc = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true);
let token = testbench.add_tc(&tc); let token = testbench.add_tc(&tc);
let (_active_req, req) = testbench let (_active_req, req) = testbench
.convert(token, &[], TEST_APID, TEST_APID_TARGET_ID) .convert(token, &[], TEST_APID, TEST_UNIQUE_ID)
.expect("conversion has failed"); .expect("conversion has failed");
assert_eq!(req, ModeRequest::AnnounceMode); assert_eq!(req, ModeRequest::AnnounceMode);
} }
@ -271,11 +405,11 @@ mod tests {
let sec_header = let sec_header =
PusTcSecondaryHeader::new_simple(200, Subservice::TcAnnounceModeRecursive as u8); PusTcSecondaryHeader::new_simple(200, Subservice::TcAnnounceModeRecursive as u8);
let mut app_data: [u8; 4] = [0; 4]; let mut app_data: [u8; 4] = [0; 4];
app_data[0..4].copy_from_slice(&TEST_APID_TARGET_ID.to_be_bytes()); app_data[0..4].copy_from_slice(&TEST_UNIQUE_ID.to_be_bytes());
let tc = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true); let tc = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true);
let token = testbench.add_tc(&tc); let token = testbench.add_tc(&tc);
let (_active_req, req) = testbench let (_active_req, req) = testbench
.convert(token, &[], TEST_APID, TEST_APID_TARGET_ID) .convert(token, &[], TEST_APID, TEST_UNIQUE_ID)
.expect("conversion has failed"); .expect("conversion has failed");
assert_eq!(req, ModeRequest::AnnounceModeRecursive); assert_eq!(req, ModeRequest::AnnounceModeRecursive);
} }
@ -283,8 +417,9 @@ mod tests {
#[test] #[test]
fn reply_handling_unrequested_reply() { fn reply_handling_unrequested_reply() {
let mut testbench = ReplyHandlerTestbench::new(ModeReplyHandler::default()); let mut testbench = ReplyHandlerTestbench::new(ModeReplyHandler::default());
let mode_reply = ModeReply::ModeInfo(ModeAndSubmode::new(5, 1)); let mode_reply = ModeReply::ModeReply(ModeAndSubmode::new(5, 1));
let unrequested_reply = GenericMessage::new(10_u32, 15_u64, mode_reply); let unrequested_reply =
GenericMessage::new(MessageMetadata::new(10_u32, 15_u64), mode_reply);
// Right now this function does not do a lot. We simply check that it does not panic or do // Right now this function does not do a lot. We simply check that it does not panic or do
// weird stuff. // weird stuff.
let result = testbench.handle_unrequested_reply(&unrequested_reply); let result = testbench.handle_unrequested_reply(&unrequested_reply);
@ -294,9 +429,14 @@ mod tests {
#[test] #[test]
fn reply_handling_reply_timeout() { fn reply_handling_reply_timeout() {
let mut testbench = ReplyHandlerTestbench::new(ModeReplyHandler::default()); let mut testbench = ReplyHandlerTestbench::new(ModeReplyHandler::default());
// TODO: Start a request, then time it out with the API and check verification completion let (req_id, active_request) = testbench.add_tc(TEST_APID, TEST_UNIQUE_ID, &[]);
// failure. let result = testbench.handle_request_timeout(&active_request, &[]);
// testbench.reply_handler.handle_request_timeout(active_request, verification_handler, time_stamp, tm_sender) assert!(result.is_ok());
// testbench.default_timeout = Duration::from_millis(50); testbench.verif_reporter.assert_completion_failure(
TEST_COMPONENT_ID.raw(),
req_id,
None,
tmtc_err::REQUEST_TIMEOUT.raw() as u64,
);
} }
} }

View File

@ -1,23 +1,18 @@
use std::sync::mpsc; use std::sync::mpsc;
use std::time::Duration; use std::time::Duration;
use crate::pus::create_verification_reporter;
use log::{error, info, warn}; use log::{error, info, warn};
use satrs::pool::{PoolProvider, StaticMemoryPool, StoreAddr}; use satrs::pool::{PoolProvider, StaticMemoryPool};
use satrs::pus::scheduler::{PusScheduler, TcInfo}; use satrs::pus::scheduler::{PusScheduler, TcInfo};
use satrs::pus::scheduler_srv::PusService11SchedHandler; use satrs::pus::scheduler_srv::PusSchedServiceHandler;
use satrs::pus::verification::std_mod::{ use satrs::pus::verification::VerificationReporter;
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender,
};
use satrs::pus::verification::VerificationReportingProvider;
use satrs::pus::{ use satrs::pus::{
EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter,
EcssTcReceiverCore, EcssTmSenderCore, MpscTcReceiver, PusPacketHandlerResult, PusServiceHelper, EcssTmSenderCore, MpscTcReceiver, MpscTmAsVecSender, MpscTmInSharedPoolSenderBounded,
TmAsVecSenderWithId, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, PusPacketHandlerResult, PusServiceHelper, PusTmAsVec, PusTmInPool, TmInSharedPoolSender,
TmInSharedPoolSenderWithId,
}; };
use satrs::tmtc::tm_helper::SharedTmPool; use satrs_example::config::components::PUS_SCHED_SERVICE;
use satrs::ComponentId;
use satrs_example::config::{ComponentIdList, PUS_APID};
use crate::tmtc::PusTcSourceProviderSharedPool; use crate::tmtc::PusTcSourceProviderSharedPool;
@ -55,14 +50,12 @@ impl TcReleaser for mpsc::Sender<Vec<u8>> {
} }
} }
pub struct Pus11Wrapper< pub struct SchedulingServiceWrapper<
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore, TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> { > {
pub pus_11_handler: PusService11SchedHandler< pub pus_11_handler: PusSchedServiceHandler<
TcReceiver, MpscTcReceiver,
TmSender, TmSender,
TcInMemConverter, TcInMemConverter,
VerificationReporter, VerificationReporter,
@ -73,12 +66,8 @@ pub struct Pus11Wrapper<
pub tc_releaser: Box<dyn TcReleaser + Send>, pub tc_releaser: Box<dyn TcReleaser + Send>,
} }
impl< impl<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter>
TcReceiver: EcssTcReceiverCore, SchedulingServiceWrapper<TmSender, TcInMemConverter>
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> Pus11Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{ {
pub fn release_tcs(&mut self) { pub fn release_tcs(&mut self) {
let releaser = |enabled: bool, info: &TcInfo, tc: &[u8]| -> bool { let releaser = |enabled: bool, info: &TcInfo, tc: &[u8]| -> bool {
@ -132,42 +121,24 @@ impl<
} }
pub fn create_scheduler_service_static( pub fn create_scheduler_service_static(
shared_tm_store: SharedTmPool, tm_sender: TmInSharedPoolSender<mpsc::SyncSender<PusTmInPool>>,
tm_funnel_tx: mpsc::SyncSender<StoreAddr>,
verif_reporter: VerificationReporterWithSharedPoolMpscBoundedSender,
tc_releaser: PusTcSourceProviderSharedPool, tc_releaser: PusTcSourceProviderSharedPool,
pus_sched_rx: mpsc::Receiver<EcssTcAndToken>, pus_sched_rx: mpsc::Receiver<EcssTcAndToken>,
sched_tc_pool: StaticMemoryPool, sched_tc_pool: StaticMemoryPool,
) -> Pus11Wrapper< ) -> SchedulingServiceWrapper<MpscTmInSharedPoolSenderBounded, EcssTcInSharedStoreConverter> {
MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc,
EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender,
> {
let sched_srv_tm_sender = TmInSharedPoolSenderWithId::new(
ComponentIdList::PusSched as ComponentId,
"PUS_11_TM_SENDER",
shared_tm_store.clone(),
tm_funnel_tx.clone(),
);
let sched_srv_receiver = MpscTcReceiver::new(
ComponentIdList::PusSched as ComponentId,
"PUS_11_TC_RECV",
pus_sched_rx,
);
let scheduler = PusScheduler::new_with_current_init_time(Duration::from_secs(5)) let scheduler = PusScheduler::new_with_current_init_time(Duration::from_secs(5))
.expect("Creating PUS Scheduler failed"); .expect("Creating PUS Scheduler failed");
let pus_11_handler = PusService11SchedHandler::new( let pus_11_handler = PusSchedServiceHandler::new(
PusServiceHelper::new( PusServiceHelper::new(
sched_srv_receiver, PUS_SCHED_SERVICE.raw(),
sched_srv_tm_sender, pus_sched_rx,
PUS_APID, tm_sender,
verif_reporter.clone(), create_verification_reporter(PUS_SCHED_SERVICE.apid),
EcssTcInSharedStoreConverter::new(tc_releaser.clone_backing_pool(), 2048), EcssTcInSharedStoreConverter::new(tc_releaser.clone_backing_pool(), 2048),
), ),
scheduler, scheduler,
); );
Pus11Wrapper { SchedulingServiceWrapper {
pus_11_handler, pus_11_handler,
sched_tc_pool, sched_tc_pool,
releaser_buf: [0; 4096], releaser_buf: [0; 4096],
@ -176,40 +147,26 @@ pub fn create_scheduler_service_static(
} }
pub fn create_scheduler_service_dynamic( pub fn create_scheduler_service_dynamic(
tm_funnel_tx: mpsc::Sender<Vec<u8>>, tm_funnel_tx: mpsc::Sender<PusTmAsVec>,
verif_reporter: VerificationReporterWithVecMpscSender,
tc_source_sender: mpsc::Sender<Vec<u8>>, tc_source_sender: mpsc::Sender<Vec<u8>>,
pus_sched_rx: mpsc::Receiver<EcssTcAndToken>, pus_sched_rx: mpsc::Receiver<EcssTcAndToken>,
sched_tc_pool: StaticMemoryPool, sched_tc_pool: StaticMemoryPool,
) -> Pus11Wrapper< ) -> SchedulingServiceWrapper<MpscTmAsVecSender, EcssTcInVecConverter> {
MpscTcReceiver, //let sched_srv_receiver =
TmAsVecSenderWithMpsc, //MpscTcReceiver::new(PUS_SCHED_SERVICE.raw(), "PUS_11_TC_RECV", pus_sched_rx);
EcssTcInVecConverter,
VerificationReporterWithVecMpscSender,
> {
let sched_srv_tm_sender = TmAsVecSenderWithId::new(
ComponentIdList::PusSched as ComponentId,
"PUS_11_TM_SENDER",
tm_funnel_tx,
);
let sched_srv_receiver = MpscTcReceiver::new(
ComponentIdList::PusSched as ComponentId,
"PUS_11_TC_RECV",
pus_sched_rx,
);
let scheduler = PusScheduler::new_with_current_init_time(Duration::from_secs(5)) let scheduler = PusScheduler::new_with_current_init_time(Duration::from_secs(5))
.expect("Creating PUS Scheduler failed"); .expect("Creating PUS Scheduler failed");
let pus_11_handler = PusService11SchedHandler::new( let pus_11_handler = PusSchedServiceHandler::new(
PusServiceHelper::new( PusServiceHelper::new(
sched_srv_receiver, PUS_SCHED_SERVICE.raw(),
sched_srv_tm_sender, pus_sched_rx,
PUS_APID, tm_funnel_tx,
verif_reporter.clone(), create_verification_reporter(PUS_SCHED_SERVICE.apid),
EcssTcInVecConverter::default(), EcssTcInVecConverter::default(),
), ),
scheduler, scheduler,
); );
Pus11Wrapper { SchedulingServiceWrapper {
pus_11_handler, pus_11_handler,
sched_tc_pool, sched_tc_pool,
releaser_buf: [0; 4096], releaser_buf: [0; 4096],

View File

@ -1,62 +1,33 @@
use crate::pus::mode::ModeServiceWrapper;
use derive_new::new;
use satrs::{ use satrs::{
pus::{ pus::{EcssTcInMemConverter, EcssTmSenderCore},
verification::VerificationReportingProvider, EcssTcInMemConverter, EcssTcReceiverCore,
EcssTmSenderCore,
},
spacepackets::time::{cds, TimeWriter}, spacepackets::time::{cds, TimeWriter},
}; };
use super::{ use super::{
action::Pus8Wrapper, event::Pus5Wrapper, hk::Pus3Wrapper, scheduler::Pus11Wrapper, action::ActionServiceWrapper, event::EventServiceWrapper, hk::HkServiceWrapper,
test::Service17CustomWrapper, TargetedPusService, scheduler::SchedulingServiceWrapper, test::TestCustomServiceWrapper, TargetedPusService,
}; };
pub struct PusStack< #[derive(new)]
TcReceiver: EcssTcReceiverCore, pub struct PusStack<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter> {
TmSender: EcssTmSenderCore, test_srv: TestCustomServiceWrapper<TmSender, TcInMemConverter>,
TcInMemConverter: EcssTcInMemConverter, hk_srv_wrapper: HkServiceWrapper<TmSender, TcInMemConverter>,
VerificationReporter: VerificationReportingProvider, event_srv: EventServiceWrapper<TmSender, TcInMemConverter>,
> { action_srv_wrapper: ActionServiceWrapper<TmSender, TcInMemConverter>,
event_srv: Pus5Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>, schedule_srv: SchedulingServiceWrapper<TmSender, TcInMemConverter>,
hk_srv_wrapper: Pus3Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>, mode_srv: ModeServiceWrapper<TmSender, TcInMemConverter>,
action_srv_wrapper: Pus8Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
schedule_srv: Pus11Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
test_srv: Service17CustomWrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
} }
impl< impl<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter>
TcReceiver: EcssTcReceiverCore, PusStack<TmSender, TcInMemConverter>
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> PusStack<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{ {
pub fn new(
hk_srv: Pus3Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
event_srv: Pus5Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
action_srv: Pus8Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
schedule_srv: Pus11Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
test_srv: Service17CustomWrapper<
TcReceiver,
TmSender,
TcInMemConverter,
VerificationReporter,
>,
) -> Self {
Self {
event_srv,
action_srv_wrapper: action_srv,
schedule_srv,
test_srv,
hk_srv_wrapper: hk_srv,
}
}
pub fn periodic_operation(&mut self) { pub fn periodic_operation(&mut self) {
// Release all telecommands which reached their release time before calling the service // Release all telecommands which reached their release time before calling the service
// handlers. // handlers.
self.schedule_srv.release_tcs(); self.schedule_srv.release_tcs();
let time_stamp = cds::TimeProvider::from_now_with_u16_days() let time_stamp = cds::CdsTime::now_with_u16_days()
.expect("time stamp generation error") .expect("time stamp generation error")
.to_vec() .to_vec()
.unwrap(); .unwrap();
@ -84,10 +55,15 @@ impl<
self.hk_srv_wrapper.poll_and_handle_next_tc(&time_stamp), self.hk_srv_wrapper.poll_and_handle_next_tc(&time_stamp),
Some(self.hk_srv_wrapper.poll_and_handle_next_reply(&time_stamp)), Some(self.hk_srv_wrapper.poll_and_handle_next_reply(&time_stamp)),
); );
is_srv_finished(
self.mode_srv.poll_and_handle_next_tc(&time_stamp),
Some(self.mode_srv.poll_and_handle_next_reply(&time_stamp)),
);
if nothing_to_do { if nothing_to_do {
// Timeout checking is only done once. // Timeout checking is only done once.
self.action_srv_wrapper.check_for_request_timeouts(); self.action_srv_wrapper.check_for_request_timeouts();
self.hk_srv_wrapper.check_for_request_timeouts(); self.hk_srv_wrapper.check_for_request_timeouts();
self.mode_srv.check_for_request_timeouts();
break; break;
} }
} }

View File

@ -1,115 +1,71 @@
use crate::pus::create_verification_reporter;
use log::{info, warn}; use log::{info, warn};
use satrs::params::Params; use satrs::params::Params;
use satrs::pool::{SharedStaticMemoryPool, StoreAddr}; use satrs::pool::SharedStaticMemoryPool;
use satrs::pus::test::PusService17TestHandler; use satrs::pus::test::PusService17TestHandler;
use satrs::pus::verification::{FailParams, VerificationReportingProvider}; use satrs::pus::verification::{FailParams, VerificationReporter, VerificationReportingProvider};
use satrs::pus::verification::{
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender,
};
use satrs::pus::{ use satrs::pus::{
EcssTcAndToken, EcssTcInMemConverter, EcssTcInVecConverter, EcssTcReceiverCore, EcssTcAndToken, EcssTcInMemConverter, EcssTcInVecConverter, EcssTmSenderCore, MpscTcReceiver,
EcssTmSenderCore, MpscTcReceiver, PusPacketHandlerResult, PusServiceHelper, MpscTmAsVecSender, MpscTmInSharedPoolSenderBounded, PusPacketHandlerResult, PusServiceHelper,
TmAsVecSenderWithId, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, PusTmAsVec, PusTmInPool, TmInSharedPoolSender,
TmInSharedPoolSenderWithId,
}; };
use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::PusPacket; use satrs::spacepackets::ecss::PusPacket;
use satrs::spacepackets::time::cds::TimeProvider; use satrs::spacepackets::time::cds::CdsTime;
use satrs::spacepackets::time::TimeWriter; use satrs::spacepackets::time::TimeWriter;
use satrs::tmtc::tm_helper::SharedTmPool;
use satrs::ComponentId;
use satrs::{events::EventU32, pus::EcssTcInSharedStoreConverter}; use satrs::{events::EventU32, pus::EcssTcInSharedStoreConverter};
use satrs_example::config::{tmtc_err, ComponentIdList, PUS_APID, TEST_EVENT}; use satrs_example::config::components::PUS_TEST_SERVICE;
use std::sync::mpsc::{self, Sender}; use satrs_example::config::{tmtc_err, TEST_EVENT};
use std::sync::mpsc;
pub fn create_test_service_static( pub fn create_test_service_static(
shared_tm_store: SharedTmPool, tm_sender: TmInSharedPoolSender<mpsc::SyncSender<PusTmInPool>>,
tm_funnel_tx: mpsc::SyncSender<StoreAddr>,
verif_reporter: VerificationReporterWithSharedPoolMpscBoundedSender,
tc_pool: SharedStaticMemoryPool, tc_pool: SharedStaticMemoryPool,
event_sender: mpsc::Sender<(EventU32, Option<Params>)>, event_sender: mpsc::Sender<(EventU32, Option<Params>)>,
pus_test_rx: mpsc::Receiver<EcssTcAndToken>, pus_test_rx: mpsc::Receiver<EcssTcAndToken>,
) -> Service17CustomWrapper< ) -> TestCustomServiceWrapper<MpscTmInSharedPoolSenderBounded, EcssTcInSharedStoreConverter> {
MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc,
EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender,
> {
let test_srv_tm_sender = TmInSharedPoolSenderWithId::new(
ComponentIdList::PusTest as ComponentId,
"PUS_17_TM_SENDER",
shared_tm_store.clone(),
tm_funnel_tx.clone(),
);
let test_srv_receiver = MpscTcReceiver::new(
ComponentIdList::PusTest as ComponentId,
"PUS_17_TC_RECV",
pus_test_rx,
);
let pus17_handler = PusService17TestHandler::new(PusServiceHelper::new( let pus17_handler = PusService17TestHandler::new(PusServiceHelper::new(
test_srv_receiver, PUS_TEST_SERVICE.raw(),
test_srv_tm_sender, pus_test_rx,
PUS_APID, tm_sender,
verif_reporter.clone(), create_verification_reporter(PUS_TEST_SERVICE.apid),
EcssTcInSharedStoreConverter::new(tc_pool, 2048), EcssTcInSharedStoreConverter::new(tc_pool, 2048),
)); ));
Service17CustomWrapper { TestCustomServiceWrapper {
handler: pus17_handler, handler: pus17_handler,
test_srv_event_sender: event_sender, test_srv_event_sender: event_sender,
} }
} }
pub fn create_test_service_dynamic( pub fn create_test_service_dynamic(
tm_funnel_tx: mpsc::Sender<Vec<u8>>, tm_funnel_tx: mpsc::Sender<PusTmAsVec>,
verif_reporter: VerificationReporterWithVecMpscSender,
event_sender: mpsc::Sender<(EventU32, Option<Params>)>, event_sender: mpsc::Sender<(EventU32, Option<Params>)>,
pus_test_rx: mpsc::Receiver<EcssTcAndToken>, pus_test_rx: mpsc::Receiver<EcssTcAndToken>,
) -> Service17CustomWrapper< ) -> TestCustomServiceWrapper<MpscTmAsVecSender, EcssTcInVecConverter> {
MpscTcReceiver,
TmAsVecSenderWithMpsc,
EcssTcInVecConverter,
VerificationReporterWithVecMpscSender,
> {
let test_srv_tm_sender = TmAsVecSenderWithId::new(
ComponentIdList::PusTest as ComponentId,
"PUS_17_TM_SENDER",
tm_funnel_tx.clone(),
);
let test_srv_receiver = MpscTcReceiver::new(
ComponentIdList::PusTest as ComponentId,
"PUS_17_TC_RECV",
pus_test_rx,
);
let pus17_handler = PusService17TestHandler::new(PusServiceHelper::new( let pus17_handler = PusService17TestHandler::new(PusServiceHelper::new(
test_srv_receiver, PUS_TEST_SERVICE.raw(),
test_srv_tm_sender, pus_test_rx,
PUS_APID, tm_funnel_tx,
verif_reporter.clone(), create_verification_reporter(PUS_TEST_SERVICE.apid),
EcssTcInVecConverter::default(), EcssTcInVecConverter::default(),
)); ));
Service17CustomWrapper { TestCustomServiceWrapper {
handler: pus17_handler, handler: pus17_handler,
test_srv_event_sender: event_sender, test_srv_event_sender: event_sender,
} }
} }
pub struct Service17CustomWrapper< pub struct TestCustomServiceWrapper<
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore, TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> { > {
pub handler: pub handler:
PusService17TestHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>, PusService17TestHandler<MpscTcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
pub test_srv_event_sender: Sender<(EventU32, Option<Params>)>, pub test_srv_event_sender: mpsc::Sender<(EventU32, Option<Params>)>,
} }
impl< impl<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter>
TcReceiver: EcssTcReceiverCore, TestCustomServiceWrapper<TmSender, TcInMemConverter>
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> Service17CustomWrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{ {
pub fn poll_and_handle_next_packet(&mut self, time_stamp: &[u8]) -> bool { pub fn poll_and_handle_next_packet(&mut self, time_stamp: &[u8]) -> bool {
let res = self.handler.poll_and_handle_next_tc(time_stamp); let res = self.handler.poll_and_handle_next_tc(time_stamp);
@ -139,7 +95,7 @@ impl<
.tc_slice_raw(), .tc_slice_raw(),
) )
.unwrap(); .unwrap();
let time_stamper = TimeProvider::from_now_with_u16_days().unwrap(); let time_stamper = CdsTime::now_with_u16_days().unwrap();
let mut stamp_buf: [u8; 7] = [0; 7]; let mut stamp_buf: [u8; 7] = [0; 7];
time_stamper.write_to_bytes(&mut stamp_buf).unwrap(); time_stamper.write_to_bytes(&mut stamp_buf).unwrap();
if subservice == 128 { if subservice == 128 {
@ -151,12 +107,22 @@ impl<
.handler .handler
.service_helper .service_helper
.verif_reporter() .verif_reporter()
.start_success(token, &stamp_buf) .start_success(
self.handler.service_helper.common.id,
self.handler.service_helper.tm_sender(),
token,
&stamp_buf,
)
.expect("Error sending start success"); .expect("Error sending start success");
self.handler self.handler
.service_helper .service_helper
.verif_reporter() .verif_reporter()
.completion_success(start_token, &stamp_buf) .completion_success(
self.handler.service_helper.id(),
self.handler.service_helper.tm_sender(),
start_token,
&stamp_buf,
)
.expect("Error sending completion success"); .expect("Error sending completion success");
} else { } else {
let fail_data = [tc.subservice()]; let fail_data = [tc.subservice()];
@ -164,6 +130,8 @@ impl<
.service_helper .service_helper
.verif_reporter() .verif_reporter()
.start_failure( .start_failure(
self.handler.service_helper.id(),
self.handler.service_helper.tm_sender(),
token, token,
FailParams::new( FailParams::new(
&stamp_buf, &stamp_buf,

View File

@ -4,15 +4,17 @@ use std::sync::mpsc;
use log::warn; use log::warn;
use satrs::action::ActionRequest; use satrs::action::ActionRequest;
use satrs::hk::HkRequest; use satrs::hk::HkRequest;
use satrs::mode::ModeRequest;
use satrs::pus::verification::{ use satrs::pus::verification::{
FailParams, TcStateAccepted, VerificationReportingProvider, VerificationToken, FailParams, TcStateAccepted, VerificationReportingProvider, VerificationToken,
}; };
use satrs::pus::{ActiveRequestProvider, GenericRoutingError, PusRequestRouter}; use satrs::pus::{ActiveRequestProvider, EcssTmSenderCore, GenericRoutingError, PusRequestRouter};
use satrs::queue::GenericSendError; use satrs::queue::GenericSendError;
use satrs::request::{GenericMessage, RequestId}; use satrs::request::{GenericMessage, MessageMetadata};
use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::PusPacket; use satrs::spacepackets::ecss::PusPacket;
use satrs::ComponentId; use satrs::ComponentId;
use satrs_example::config::components::PUS_ROUTING_SERVICE;
use satrs_example::config::tmtc_err; use satrs_example::config::tmtc_err;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -22,19 +24,32 @@ pub enum CompositeRequest {
Action(ActionRequest), Action(ActionRequest),
} }
#[derive(Default, Clone)] #[derive(Clone)]
pub struct GenericRequestRouter( pub struct GenericRequestRouter {
pub HashMap<ComponentId, mpsc::Sender<GenericMessage<CompositeRequest>>>, pub id: ComponentId,
); // All messages which do not have a dedicated queue.
pub composite_router_map: HashMap<ComponentId, mpsc::Sender<GenericMessage<CompositeRequest>>>,
pub mode_router_map: HashMap<ComponentId, mpsc::Sender<GenericMessage<ModeRequest>>>,
}
impl Default for GenericRequestRouter {
fn default() -> Self {
Self {
id: PUS_ROUTING_SERVICE.raw(),
composite_router_map: Default::default(),
mode_router_map: Default::default(),
}
}
}
impl GenericRequestRouter { impl GenericRequestRouter {
pub(crate) fn handle_error_generic( pub(crate) fn handle_error_generic(
&self, &self,
active_request: &impl ActiveRequestProvider, active_request: &impl ActiveRequestProvider,
tc: &PusTcReader, tc: &PusTcReader,
error: GenericRoutingError, error: GenericRoutingError,
time_stamp: &[u8], tm_sender: &(impl EcssTmSenderCore + ?Sized),
verif_reporter: &impl VerificationReportingProvider, verif_reporter: &impl VerificationReportingProvider,
time_stamp: &[u8],
) { ) {
warn!( warn!(
"Routing request for service {} failed: {error:?}", "Routing request for service {} failed: {error:?}",
@ -50,6 +65,8 @@ impl GenericRequestRouter {
fail_data.copy_from_slice(&id.to_be_bytes()); fail_data.copy_from_slice(&id.to_be_bytes());
verif_reporter verif_reporter
.completion_failure( .completion_failure(
self.id,
tm_sender,
accepted_token, accepted_token,
FailParams::new(time_stamp, &tmtc_err::UNKNOWN_TARGET_ID, &fail_data), FailParams::new(time_stamp, &tmtc_err::UNKNOWN_TARGET_ID, &fail_data),
) )
@ -60,6 +77,8 @@ impl GenericRequestRouter {
fail_data.copy_from_slice(&active_request.target_id().to_be_bytes()); fail_data.copy_from_slice(&active_request.target_id().to_be_bytes());
verif_reporter verif_reporter
.completion_failure( .completion_failure(
self.id,
tm_sender,
accepted_token, accepted_token,
FailParams::new(time_stamp, &tmtc_err::ROUTING_ERROR, &fail_data), FailParams::new(time_stamp, &tmtc_err::ROUTING_ERROR, &fail_data),
) )
@ -73,16 +92,14 @@ impl PusRequestRouter<HkRequest> for GenericRequestRouter {
fn route( fn route(
&self, &self,
request_id: RequestId, requestor_info: MessageMetadata,
source_id: ComponentId,
target_id: ComponentId, target_id: ComponentId,
hk_request: HkRequest, hk_request: HkRequest,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
if let Some(sender) = self.0.get(&target_id) { if let Some(sender) = self.composite_router_map.get(&target_id) {
sender sender
.send(GenericMessage::new( .send(GenericMessage::new(
request_id, requestor_info,
source_id,
CompositeRequest::Hk(hk_request), CompositeRequest::Hk(hk_request),
)) ))
.map_err(|_| GenericRoutingError::Send(GenericSendError::RxDisconnected))?; .map_err(|_| GenericRoutingError::Send(GenericSendError::RxDisconnected))?;
@ -97,16 +114,14 @@ impl PusRequestRouter<ActionRequest> for GenericRequestRouter {
fn route( fn route(
&self, &self,
request_id: RequestId, requestor_info: MessageMetadata,
source_id: ComponentId,
target_id: ComponentId, target_id: ComponentId,
action_request: ActionRequest, action_request: ActionRequest,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
if let Some(sender) = self.0.get(&target_id) { if let Some(sender) = self.composite_router_map.get(&target_id) {
sender sender
.send(GenericMessage::new( .send(GenericMessage::new(
request_id, requestor_info,
source_id,
CompositeRequest::Action(action_request), CompositeRequest::Action(action_request),
)) ))
.map_err(|_| GenericRoutingError::Send(GenericSendError::RxDisconnected))?; .map_err(|_| GenericRoutingError::Send(GenericSendError::RxDisconnected))?;
@ -115,3 +130,22 @@ impl PusRequestRouter<ActionRequest> for GenericRequestRouter {
Err(GenericRoutingError::UnknownTargetId(target_id)) Err(GenericRoutingError::UnknownTargetId(target_id))
} }
} }
impl PusRequestRouter<ModeRequest> for GenericRequestRouter {
type Error = GenericRoutingError;
fn route(
&self,
requestor_info: MessageMetadata,
target_id: ComponentId,
request: ModeRequest,
) -> Result<(), Self::Error> {
if let Some(sender) = self.mode_router_map.get(&target_id) {
sender
.send(GenericMessage::new(requestor_info, request))
.map_err(|_| GenericRoutingError::Send(GenericSendError::RxDisconnected))?;
return Ok(());
}
Err(GenericRoutingError::UnknownTargetId(target_id))
}
}

View File

@ -10,11 +10,16 @@ use satrs::{
spacepackets::PacketId, spacepackets::PacketId,
tmtc::{CcsdsDistributor, CcsdsError, ReceivesCcsdsTc, TmPacketSourceCore}, tmtc::{CcsdsDistributor, CcsdsError, ReceivesCcsdsTc, TmPacketSourceCore},
}; };
use satrs_example::config::PUS_APID; use satrs_example::config::components;
use crate::ccsds::CcsdsReceiver; use crate::ccsds::CcsdsReceiver;
pub const PACKET_ID_LOOKUP: &[PacketId] = &[PacketId::const_tc(true, PUS_APID)]; pub const PACKET_ID_LOOKUP: &[PacketId] = &[
PacketId::const_tc(true, components::Apid::GenericPus as u16),
PacketId::const_tc(true, components::Apid::EventTm as u16),
PacketId::const_tc(true, components::Apid::Acs as u16),
PacketId::const_tc(true, components::Apid::Sched as u16),
];
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct SyncTcpTmSource { pub struct SyncTcpTmSource {

View File

@ -4,8 +4,9 @@ use std::{
}; };
use log::info; use log::info;
use satrs::pus::{PusTmAsVec, PusTmInPool};
use satrs::{ use satrs::{
pool::{PoolProvider, StoreAddr}, pool::PoolProvider,
seq_count::{CcsdsSimpleSeqCountProvider, SequenceCountProviderCore}, seq_count::{CcsdsSimpleSeqCountProvider, SequenceCountProviderCore},
spacepackets::{ spacepackets::{
ecss::{tm::PusTmZeroCopyWriter, PusPacket}, ecss::{tm::PusTmZeroCopyWriter, PusPacket},
@ -77,16 +78,16 @@ impl TmFunnelCommon {
pub struct TmFunnelStatic { pub struct TmFunnelStatic {
common: TmFunnelCommon, common: TmFunnelCommon,
shared_tm_store: SharedTmPool, shared_tm_store: SharedTmPool,
tm_funnel_rx: mpsc::Receiver<StoreAddr>, tm_funnel_rx: mpsc::Receiver<PusTmInPool>,
tm_server_tx: mpsc::SyncSender<StoreAddr>, tm_server_tx: mpsc::SyncSender<PusTmInPool>,
} }
impl TmFunnelStatic { impl TmFunnelStatic {
pub fn new( pub fn new(
shared_tm_store: SharedTmPool, shared_tm_store: SharedTmPool,
sync_tm_tcp_source: SyncTcpTmSource, sync_tm_tcp_source: SyncTcpTmSource,
tm_funnel_rx: mpsc::Receiver<StoreAddr>, tm_funnel_rx: mpsc::Receiver<PusTmInPool>,
tm_server_tx: mpsc::SyncSender<StoreAddr>, tm_server_tx: mpsc::SyncSender<PusTmInPool>,
) -> Self { ) -> Self {
Self { Self {
common: TmFunnelCommon::new(sync_tm_tcp_source), common: TmFunnelCommon::new(sync_tm_tcp_source),
@ -97,14 +98,14 @@ impl TmFunnelStatic {
} }
pub fn operation(&mut self) { pub fn operation(&mut self) {
if let Ok(addr) = self.tm_funnel_rx.recv() { if let Ok(pus_tm_in_pool) = self.tm_funnel_rx.recv() {
// Read the TM, set sequence counter and message counter, and finally update // Read the TM, set sequence counter and message counter, and finally update
// the CRC. // the CRC.
let shared_pool = self.shared_tm_store.clone_backing_pool(); let shared_pool = self.shared_tm_store.clone_backing_pool();
let mut pool_guard = shared_pool.write().expect("Locking TM pool failed"); let mut pool_guard = shared_pool.write().expect("Locking TM pool failed");
let mut tm_copy = Vec::new(); let mut tm_copy = Vec::new();
pool_guard pool_guard
.modify(&addr, |buf| { .modify(&pus_tm_in_pool.store_addr, |buf| {
let zero_copy_writer = PusTmZeroCopyWriter::new(buf, MIN_CDS_FIELD_LEN) let zero_copy_writer = PusTmZeroCopyWriter::new(buf, MIN_CDS_FIELD_LEN)
.expect("Creating TM zero copy writer failed"); .expect("Creating TM zero copy writer failed");
self.common.apply_packet_processing(zero_copy_writer); self.common.apply_packet_processing(zero_copy_writer);
@ -112,7 +113,7 @@ impl TmFunnelStatic {
}) })
.expect("Reading TM from pool failed"); .expect("Reading TM from pool failed");
self.tm_server_tx self.tm_server_tx
.send(addr) .send(pus_tm_in_pool)
.expect("Sending TM to server failed"); .expect("Sending TM to server failed");
// We could also do this step in the update closure, but I'd rather avoid this, could // We could also do this step in the update closure, but I'd rather avoid this, could
// lead to nested locking. // lead to nested locking.
@ -123,15 +124,15 @@ impl TmFunnelStatic {
pub struct TmFunnelDynamic { pub struct TmFunnelDynamic {
common: TmFunnelCommon, common: TmFunnelCommon,
tm_funnel_rx: mpsc::Receiver<Vec<u8>>, tm_funnel_rx: mpsc::Receiver<PusTmAsVec>,
tm_server_tx: mpsc::Sender<Vec<u8>>, tm_server_tx: mpsc::Sender<PusTmAsVec>,
} }
impl TmFunnelDynamic { impl TmFunnelDynamic {
pub fn new( pub fn new(
sync_tm_tcp_source: SyncTcpTmSource, sync_tm_tcp_source: SyncTcpTmSource,
tm_funnel_rx: mpsc::Receiver<Vec<u8>>, tm_funnel_rx: mpsc::Receiver<PusTmAsVec>,
tm_server_tx: mpsc::Sender<Vec<u8>>, tm_server_tx: mpsc::Sender<PusTmAsVec>,
) -> Self { ) -> Self {
Self { Self {
common: TmFunnelCommon::new(sync_tm_tcp_source), common: TmFunnelCommon::new(sync_tm_tcp_source),
@ -144,13 +145,13 @@ impl TmFunnelDynamic {
if let Ok(mut tm) = self.tm_funnel_rx.recv() { if let Ok(mut tm) = self.tm_funnel_rx.recv() {
// Read the TM, set sequence counter and message counter, and finally update // Read the TM, set sequence counter and message counter, and finally update
// the CRC. // the CRC.
let zero_copy_writer = PusTmZeroCopyWriter::new(&mut tm, MIN_CDS_FIELD_LEN) let zero_copy_writer = PusTmZeroCopyWriter::new(&mut tm.packet, MIN_CDS_FIELD_LEN)
.expect("Creating TM zero copy writer failed"); .expect("Creating TM zero copy writer failed");
self.common.apply_packet_processing(zero_copy_writer); self.common.apply_packet_processing(zero_copy_writer);
self.common.sync_tm_tcp_source.add_tm(&tm.packet);
self.tm_server_tx self.tm_server_tx
.send(tm.clone()) .send(tm)
.expect("Sending TM to server failed"); .expect("Sending TM to server failed");
self.common.sync_tm_tcp_source.add_tm(&tm);
} }
} }
} }

View File

@ -1,8 +1,7 @@
use log::warn; use log::warn;
use satrs::pus::verification::std_mod::{ use satrs::pus::{
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender, EcssTcAndToken, MpscTmAsVecSender, MpscTmInSharedPoolSenderBounded, ReceivesEcssPusTc,
}; };
use satrs::pus::{EcssTcAndToken, ReceivesEcssPusTc};
use satrs::spacepackets::SpHeader; use satrs::spacepackets::SpHeader;
use std::sync::mpsc::{self, Receiver, SendError, Sender, SyncSender, TryRecvError}; use std::sync::mpsc::{self, Receiver, SendError, Sender, SyncSender, TryRecvError};
use thiserror::Error; use thiserror::Error;
@ -100,14 +99,14 @@ pub struct TcSourceTaskStatic {
shared_tc_pool: SharedTcPool, shared_tc_pool: SharedTcPool,
tc_receiver: Receiver<StoreAddr>, tc_receiver: Receiver<StoreAddr>,
tc_buf: [u8; 4096], tc_buf: [u8; 4096],
pus_receiver: PusReceiver<VerificationReporterWithSharedPoolMpscBoundedSender>, pus_receiver: PusReceiver<MpscTmInSharedPoolSenderBounded>,
} }
impl TcSourceTaskStatic { impl TcSourceTaskStatic {
pub fn new( pub fn new(
shared_tc_pool: SharedTcPool, shared_tc_pool: SharedTcPool,
tc_receiver: Receiver<StoreAddr>, tc_receiver: Receiver<StoreAddr>,
pus_receiver: PusReceiver<VerificationReporterWithSharedPoolMpscBoundedSender>, pus_receiver: PusReceiver<MpscTmInSharedPoolSenderBounded>,
) -> Self { ) -> Self {
Self { Self {
shared_tc_pool, shared_tc_pool,
@ -164,13 +163,13 @@ impl TcSourceTaskStatic {
// TC source components where the heap is the backing memory of the received telecommands. // TC source components where the heap is the backing memory of the received telecommands.
pub struct TcSourceTaskDynamic { pub struct TcSourceTaskDynamic {
pub tc_receiver: Receiver<Vec<u8>>, pub tc_receiver: Receiver<Vec<u8>>,
pus_receiver: PusReceiver<VerificationReporterWithVecMpscSender>, pus_receiver: PusReceiver<MpscTmAsVecSender>,
} }
impl TcSourceTaskDynamic { impl TcSourceTaskDynamic {
pub fn new( pub fn new(
tc_receiver: Receiver<Vec<u8>>, tc_receiver: Receiver<Vec<u8>>,
pus_receiver: PusReceiver<VerificationReporterWithVecMpscSender>, pus_receiver: PusReceiver<MpscTmAsVecSender>,
) -> Self { ) -> Self {
Self { Self {
tc_receiver, tc_receiver,

View File

@ -1,12 +1,11 @@
use std::{ use std::net::{SocketAddr, UdpSocket};
net::{SocketAddr, UdpSocket}, use std::sync::mpsc;
sync::mpsc::Receiver,
};
use log::{info, warn}; use log::{info, warn};
use satrs::pus::{PusTmAsVec, PusTmInPool};
use satrs::{ use satrs::{
hal::std::udp_server::{ReceiveResult, UdpTcServer}, hal::std::udp_server::{ReceiveResult, UdpTcServer},
pool::{PoolProviderWithGuards, SharedStaticMemoryPool, StoreAddr}, pool::{PoolProviderWithGuards, SharedStaticMemoryPool},
tmtc::CcsdsError, tmtc::CcsdsError,
}; };
@ -15,20 +14,20 @@ pub trait UdpTmHandler {
} }
pub struct StaticUdpTmHandler { pub struct StaticUdpTmHandler {
pub tm_rx: Receiver<StoreAddr>, pub tm_rx: mpsc::Receiver<PusTmInPool>,
pub tm_store: SharedStaticMemoryPool, pub tm_store: SharedStaticMemoryPool,
} }
impl UdpTmHandler for StaticUdpTmHandler { impl UdpTmHandler for StaticUdpTmHandler {
fn send_tm_to_udp_client(&mut self, socket: &UdpSocket, &recv_addr: &SocketAddr) { fn send_tm_to_udp_client(&mut self, socket: &UdpSocket, &recv_addr: &SocketAddr) {
while let Ok(addr) = self.tm_rx.try_recv() { while let Ok(pus_tm_in_pool) = self.tm_rx.try_recv() {
let store_lock = self.tm_store.write(); let store_lock = self.tm_store.write();
if store_lock.is_err() { if store_lock.is_err() {
warn!("Locking TM store failed"); warn!("Locking TM store failed");
continue; continue;
} }
let mut store_lock = store_lock.unwrap(); let mut store_lock = store_lock.unwrap();
let pg = store_lock.read_with_guard(addr); let pg = store_lock.read_with_guard(pus_tm_in_pool.store_addr);
let read_res = pg.read_as_vec(); let read_res = pg.read_as_vec();
if read_res.is_err() { if read_res.is_err() {
warn!("Error reading TM pool data"); warn!("Error reading TM pool data");
@ -44,20 +43,20 @@ impl UdpTmHandler for StaticUdpTmHandler {
} }
pub struct DynamicUdpTmHandler { pub struct DynamicUdpTmHandler {
pub tm_rx: Receiver<Vec<u8>>, pub tm_rx: mpsc::Receiver<PusTmAsVec>,
} }
impl UdpTmHandler for DynamicUdpTmHandler { impl UdpTmHandler for DynamicUdpTmHandler {
fn send_tm_to_udp_client(&mut self, socket: &UdpSocket, recv_addr: &SocketAddr) { fn send_tm_to_udp_client(&mut self, socket: &UdpSocket, recv_addr: &SocketAddr) {
while let Ok(tm) = self.tm_rx.try_recv() { while let Ok(tm) = self.tm_rx.try_recv() {
if tm.len() > 9 { if tm.packet.len() > 9 {
let service = tm[7]; let service = tm.packet[7];
let subservice = tm[8]; let subservice = tm.packet[8];
info!("Sending PUS TM[{service},{subservice}]") info!("Sending PUS TM[{service},{subservice}]")
} else { } else {
info!("Sending PUS TM"); info!("Sending PUS TM");
} }
let result = socket.send_to(&tm, recv_addr); let result = socket.send_to(&tm.packet, recv_addr);
if let Err(e) = result { if let Err(e) = result {
warn!("Sending TM with UDP socket failed: {e}") warn!("Sending TM with UDP socket failed: {e}")
} }
@ -120,7 +119,7 @@ mod tests {
}, },
tmtc::ReceivesTcCore, tmtc::ReceivesTcCore,
}; };
use satrs_example::config::{OBSW_SERVER_ADDR, PUS_APID}; use satrs_example::config::{components, OBSW_SERVER_ADDR};
use super::*; use super::*;
@ -178,7 +177,7 @@ mod tests {
udp_tc_server, udp_tc_server,
tm_handler, tm_handler,
}; };
let mut sph = SpHeader::tc_unseg(PUS_APID, 0, 0).unwrap(); let mut sph = SpHeader::tc_unseg(components::Apid::GenericPus as u16, 0, 0).unwrap();
let ping_tc = PusTcCreator::new_simple(&mut sph, 17, 1, None, true) let ping_tc = PusTcCreator::new_simple(&mut sph, 17, 1, None, true)
.to_vec() .to_vec()
.unwrap(); .unwrap();

View File

@ -28,7 +28,6 @@ features = ["full"]
trybuild = { version = "1", features = ["diff"] } trybuild = { version = "1", features = ["diff"] }
[dev-dependencies.satrs-shared] [dev-dependencies.satrs-shared]
# satrs-shared = "0.1.2"
path = "../../satrs-shared" path = "../../satrs-shared"
version = "0.1.3" version = "0.1.3"

View File

@ -18,7 +18,9 @@ default-features = false
optional = true optional = true
[dependencies.spacepackets] [dependencies.spacepackets]
git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git"
version = "0.11.0-rc.0" version = "0.11.0-rc.0"
branch = "main"
default-features = false default-features = false
[features] [features]

View File

@ -71,7 +71,9 @@ features = ["all"]
optional = true optional = true
[dependencies.spacepackets] [dependencies.spacepackets]
git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git"
version = "0.11.0-rc.0" version = "0.11.0-rc.0"
branch = "main"
default-features = false default-features = false
[dependencies.cobs] [dependencies.cobs]

View File

@ -19,8 +19,8 @@ impl HkRequest {
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum HkRequestVariant { pub enum HkRequestVariant {
OneShot, OneShot,
Enable, EnablePeriodic,
Disable, DisablePeriodic,
ModifyCollectionInterval(CollectionIntervalFactor), ModifyCollectionInterval(CollectionIntervalFactor),
} }

View File

@ -12,7 +12,7 @@ pub use std_mod::*;
use crate::{ use crate::{
queue::GenericTargetedMessagingError, queue::GenericTargetedMessagingError,
request::{GenericMessage, MessageReceiver, MessageReceiverWithId, RequestId}, request::{GenericMessage, MessageMetadata, MessageReceiver, MessageReceiverWithId, RequestId},
ComponentId, ComponentId,
}; };
@ -109,6 +109,8 @@ impl TargetedModeCommand {
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ModeRequest { pub enum ModeRequest {
/// Mode information. Can be used to notify other components of changed modes.
ModeInfo(ModeAndSubmode),
SetMode(ModeAndSubmode), SetMode(ModeAndSubmode),
ReadMode, ReadMode,
AnnounceMode, AnnounceMode,
@ -125,8 +127,6 @@ pub struct TargetedModeRequest {
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ModeReply { pub enum ModeReply {
/// Unrequest mode information. Can be used to notify other components of changed modes.
ModeInfo(ModeAndSubmode),
/// Reply to a mode request to confirm the commanded mode was reached. /// Reply to a mode request to confirm the commanded mode was reached.
ModeReply(ModeAndSubmode), ModeReply(ModeAndSubmode),
// Can not reach the commanded mode. Contains a reason as a [ResultU16]. // Can not reach the commanded mode. Contains a reason as a [ResultU16].
@ -184,13 +184,20 @@ impl From<GenericTargetedMessagingError> for ModeError {
pub trait ModeRequestHandler: ModeProvider { pub trait ModeRequestHandler: ModeProvider {
fn start_transition( fn start_transition(
&mut self, &mut self,
request_id: RequestId, requestor: MessageMetadata,
sender_id: ComponentId,
mode_and_submode: ModeAndSubmode, mode_and_submode: ModeAndSubmode,
) -> Result<(), ModeError>; ) -> Result<(), ModeError>;
fn announce_mode(&self, request_id: RequestId, sender_id: ComponentId, recursive: bool); fn announce_mode(&self, requestor_info: MessageMetadata, recursive: bool);
fn handle_mode_reached(&mut self) -> Result<(), GenericTargetedMessagingError>; fn handle_mode_reached(
&mut self,
requestor_info: Option<MessageMetadata>,
) -> Result<(), GenericTargetedMessagingError>;
fn send_mode_reply(
&self,
requestor_info: MessageMetadata,
reply: ModeReply,
) -> Result<(), GenericTargetedMessagingError>;
} }
pub trait ModeReplyReceiver { pub trait ModeReplyReceiver {
@ -210,10 +217,10 @@ impl<R: MessageReceiver<ModeReply>> ModeReplyReceiver for MessageReceiverWithId<
pub trait ModeReplySender { pub trait ModeReplySender {
fn local_channel_id(&self) -> ComponentId; fn local_channel_id(&self) -> ComponentId;
/// The requestor is assumed to be the target of the reply.
fn send_mode_reply( fn send_mode_reply(
&self, &self,
request_id: RequestId, requestor_info: MessageMetadata,
target_id: ComponentId,
reply: ModeReply, reply: ModeReply,
) -> Result<(), GenericTargetedMessagingError>; ) -> Result<(), GenericTargetedMessagingError>;
} }
@ -225,7 +232,7 @@ pub mod alloc_mod {
mode::ModeRequest, mode::ModeRequest,
queue::GenericTargetedMessagingError, queue::GenericTargetedMessagingError,
request::{ request::{
MessageSender, MessageSenderAndReceiver, MessageSenderMap, MessageSenderMapWithId, MessageMetadata, MessageSender, MessageSenderAndReceiver, MessageSenderMap,
RequestAndReplySenderAndReceiver, RequestId, RequestAndReplySenderAndReceiver, RequestId,
}, },
ComponentId, ComponentId,
@ -236,12 +243,11 @@ pub mod alloc_mod {
impl<S: MessageSender<ModeReply>> MessageSenderMap<ModeReply, S> { impl<S: MessageSender<ModeReply>> MessageSenderMap<ModeReply, S> {
pub fn send_mode_reply( pub fn send_mode_reply(
&self, &self,
request_id: RequestId, requestor_info: MessageMetadata,
local_id: ComponentId,
target_id: ComponentId, target_id: ComponentId,
request: ModeReply, request: ModeReply,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
self.send_message(request_id, local_id, target_id, request) self.send_message(requestor_info, target_id, request)
} }
pub fn add_reply_target(&mut self, target_id: ComponentId, request_sender: S) { pub fn add_reply_target(&mut self, target_id: ComponentId, request_sender: S) {
@ -249,6 +255,7 @@ pub mod alloc_mod {
} }
} }
/*
impl<S: MessageSender<ModeReply>> ModeReplySender for MessageSenderMapWithId<ModeReply, S> { impl<S: MessageSender<ModeReply>> ModeReplySender for MessageSenderMapWithId<ModeReply, S> {
fn send_mode_reply( fn send_mode_reply(
&self, &self,
@ -263,6 +270,7 @@ pub mod alloc_mod {
self.local_channel_id self.local_channel_id
} }
} }
*/
impl<FROM, S: MessageSender<ModeReply>, R: MessageReceiver<FROM>> ModeReplySender impl<FROM, S: MessageSender<ModeReply>, R: MessageReceiver<FROM>> ModeReplySender
for MessageSenderAndReceiver<ModeReply, FROM, S, R> for MessageSenderAndReceiver<ModeReply, FROM, S, R>
@ -273,14 +281,12 @@ pub mod alloc_mod {
fn send_mode_reply( fn send_mode_reply(
&self, &self,
request_id: RequestId, requestor_info: MessageMetadata,
target_id: ComponentId,
request: ModeReply, request: ModeReply,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
self.message_sender_map.send_mode_reply( self.message_sender_map.send_mode_reply(
request_id, MessageMetadata::new(requestor_info.request_id(), self.local_channel_id()),
self.local_channel_id(), requestor_info.sender_id(),
target_id,
request, request,
) )
} }
@ -324,14 +330,12 @@ pub mod alloc_mod {
fn send_mode_reply( fn send_mode_reply(
&self, &self,
request_id: RequestId, requestor_info: MessageMetadata,
target_id: ComponentId,
request: ModeReply, request: ModeReply,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
self.reply_sender_map.send_mode_reply( self.reply_sender_map.send_mode_reply(
request_id, MessageMetadata::new(requestor_info.request_id(), self.local_channel_id()),
self.local_channel_id(), requestor_info.sender_id(),
target_id,
request, request,
) )
} }
@ -368,11 +372,14 @@ pub mod alloc_mod {
pub fn send_mode_reply( pub fn send_mode_reply(
&self, &self,
request_id: RequestId, requestor_info: MessageMetadata,
target_id: ComponentId,
reply: ModeReply, reply: ModeReply,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
self.send_message(request_id, target_id, reply) self.send_message(
requestor_info.request_id(),
requestor_info.sender_id(),
reply,
)
} }
} }
@ -405,12 +412,11 @@ pub mod alloc_mod {
impl<S: MessageSender<ModeRequest>> MessageSenderMap<ModeRequest, S> { impl<S: MessageSender<ModeRequest>> MessageSenderMap<ModeRequest, S> {
pub fn send_mode_request( pub fn send_mode_request(
&self, &self,
request_id: RequestId, requestor_info: MessageMetadata,
local_id: ComponentId,
target_id: ComponentId, target_id: ComponentId,
request: ModeRequest, request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
self.send_message(request_id, local_id, target_id, request) self.send_message(requestor_info, target_id, request)
} }
pub fn add_request_target(&mut self, target_id: ComponentId, request_sender: S) { pub fn add_request_target(&mut self, target_id: ComponentId, request_sender: S) {
@ -418,6 +424,7 @@ pub mod alloc_mod {
} }
} }
/*
impl<S: MessageSender<ModeRequest>> ModeRequestSender for MessageSenderMapWithId<ModeRequest, S> { impl<S: MessageSender<ModeRequest>> ModeRequestSender for MessageSenderMapWithId<ModeRequest, S> {
fn local_channel_id(&self) -> ComponentId { fn local_channel_id(&self) -> ComponentId {
self.local_channel_id self.local_channel_id
@ -432,6 +439,7 @@ pub mod alloc_mod {
self.send_message(request_id, target_id, request) self.send_message(request_id, target_id, request)
} }
} }
*/
impl<TO, S: MessageSender<TO>, R: MessageReceiver<ModeRequest>> ModeRequestReceiver impl<TO, S: MessageSender<TO>, R: MessageReceiver<ModeRequest>> ModeRequestReceiver
for MessageSenderAndReceiver<TO, ModeRequest, S, R> for MessageSenderAndReceiver<TO, ModeRequest, S, R>
@ -457,8 +465,7 @@ pub mod alloc_mod {
request: ModeRequest, request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
self.message_sender_map.send_mode_request( self.message_sender_map.send_mode_request(
request_id, MessageMetadata::new(request_id, self.local_channel_id()),
self.local_channel_id(),
target_id, target_id,
request, request,
) )
@ -499,8 +506,7 @@ pub mod alloc_mod {
request: ModeRequest, request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
self.request_sender_map.send_mode_request( self.request_sender_map.send_mode_request(
request_id, MessageMetadata::new(request_id, self.local_channel_id()),
self.local_channel_id(),
target_id, target_id,
request, request,
) )

View File

@ -1,8 +1,7 @@
use crate::{ use crate::{
action::{ActionId, ActionRequest}, action::{ActionId, ActionRequest},
params::Params, params::Params,
request::{GenericMessage, RequestId}, request::{GenericMessage, MessageMetadata, RequestId},
ComponentId,
}; };
use satrs_shared::res_code::ResultU16; use satrs_shared::res_code::ResultU16;
@ -57,12 +56,11 @@ pub type GenericActionReplyPus = GenericMessage<PusActionReply>;
impl GenericActionReplyPus { impl GenericActionReplyPus {
pub fn new_action_reply( pub fn new_action_reply(
request_id: RequestId, requestor_info: MessageMetadata,
sender_id: ComponentId,
action_id: ActionId, action_id: ActionId,
reply: ActionReplyVariant, reply: ActionReplyVariant,
) -> Self { ) -> Self {
Self::new(request_id, sender_id, PusActionReply::new(action_id, reply)) Self::new(requestor_info, PusActionReply::new(action_id, reply))
} }
} }

View File

@ -2,6 +2,7 @@ use crate::pus::{source_buffer_large_enough, EcssTmtcError};
use spacepackets::ecss::tm::PusTmCreator; use spacepackets::ecss::tm::PusTmCreator;
use spacepackets::ecss::tm::PusTmSecondaryHeader; use spacepackets::ecss::tm::PusTmSecondaryHeader;
use spacepackets::ecss::{EcssEnumeration, PusError}; use spacepackets::ecss::{EcssEnumeration, PusError};
use spacepackets::ByteConversionError;
use spacepackets::{SpHeader, MAX_APID}; use spacepackets::{SpHeader, MAX_APID};
use crate::pus::EcssTmSenderCore; use crate::pus::EcssTmSenderCore;
@ -9,145 +10,125 @@ use crate::pus::EcssTmSenderCore;
pub use alloc_mod::EventReporter; pub use alloc_mod::EventReporter;
pub use spacepackets::ecss::event::*; pub use spacepackets::ecss::event::*;
pub struct EventReporterBase { pub struct EventReportCreator {
msg_count: u16,
apid: u16, apid: u16,
pub dest_id: u16, pub dest_id: u16,
} }
impl EventReporterBase { impl EventReportCreator {
pub fn new(apid: u16) -> Option<Self> { pub fn new(apid: u16) -> Option<Self> {
if apid > MAX_APID { if apid > MAX_APID {
return None; return None;
} }
Some(Self { Some(Self {
msg_count: 0, // msg_count: 0,
dest_id: 0, dest_id: 0,
apid, apid,
}) })
} }
pub fn event_info( pub fn event_info<'time, 'src_data>(
&mut self, &self,
buf: &mut [u8], src_data_buf: &'src_data mut [u8],
sender: &mut (impl EcssTmSenderCore + ?Sized), time_stamp: &'time [u8],
time_stamp: &[u8],
event_id: impl EcssEnumeration, event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>, aux_data: Option<&'src_data [u8]>,
) -> Result<(), EcssTmtcError> { ) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_and_send_generic_tm( self.generate_and_send_generic_tm(
buf, src_data_buf,
Subservice::TmInfoReport, Subservice::TmInfoReport,
sender,
time_stamp, time_stamp,
event_id, event_id,
aux_data, aux_data,
) )
} }
pub fn event_low_severity( pub fn event_low_severity<'time, 'src_data>(
&mut self, &self,
buf: &mut [u8], src_data_buf: &'src_data mut [u8],
sender: &mut (impl EcssTmSenderCore + ?Sized), time_stamp: &'time [u8],
time_stamp: &[u8],
event_id: impl EcssEnumeration, event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>, aux_data: Option<&'src_data [u8]>,
) -> Result<(), EcssTmtcError> { ) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_and_send_generic_tm( self.generate_and_send_generic_tm(
buf, src_data_buf,
Subservice::TmLowSeverityReport, Subservice::TmLowSeverityReport,
sender,
time_stamp, time_stamp,
event_id, event_id,
aux_data, aux_data,
) )
} }
pub fn event_medium_severity( pub fn event_medium_severity<'time, 'src_data>(
&mut self, &self,
buf: &mut [u8], buf: &'src_data mut [u8],
sender: &mut (impl EcssTmSenderCore + ?Sized), time_stamp: &'time [u8],
time_stamp: &[u8],
event_id: impl EcssEnumeration, event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>, aux_data: Option<&'src_data [u8]>,
) -> Result<(), EcssTmtcError> { ) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_and_send_generic_tm( self.generate_and_send_generic_tm(
buf, buf,
Subservice::TmMediumSeverityReport, Subservice::TmMediumSeverityReport,
sender,
time_stamp, time_stamp,
event_id, event_id,
aux_data, aux_data,
) )
} }
pub fn event_high_severity( pub fn event_high_severity<'time, 'src_data>(
&mut self, &self,
buf: &mut [u8], src_data_buf: &'src_data mut [u8],
sender: &mut (impl EcssTmSenderCore + ?Sized), time_stamp: &'time [u8],
time_stamp: &[u8],
event_id: impl EcssEnumeration, event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>, aux_data: Option<&'src_data [u8]>,
) -> Result<(), EcssTmtcError> { ) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_and_send_generic_tm( self.generate_and_send_generic_tm(
buf, src_data_buf,
Subservice::TmHighSeverityReport, Subservice::TmHighSeverityReport,
sender,
time_stamp, time_stamp,
event_id, event_id,
aux_data, aux_data,
) )
} }
fn generate_and_send_generic_tm( fn generate_and_send_generic_tm<'time, 'src_data>(
&mut self, &self,
buf: &mut [u8], src_data_buf: &'src_data mut [u8],
subservice: Subservice, subservice: Subservice,
sender: &mut (impl EcssTmSenderCore + ?Sized), time_stamp: &'time [u8],
time_stamp: &[u8],
event_id: impl EcssEnumeration, event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>, aux_data: Option<&'src_data [u8]>,
) -> Result<(), EcssTmtcError> { ) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
let tm = self.generate_generic_event_tm(buf, subservice, time_stamp, event_id, aux_data)?; self.generate_generic_event_tm(src_data_buf, subservice, time_stamp, event_id, aux_data)
sender.send_tm(tm.into())?;
self.msg_count += 1;
Ok(())
} }
fn generate_generic_event_tm<'a>( fn generate_generic_event_tm<'time, 'src_data>(
&'a self, &self,
buf: &'a mut [u8], src_data_buf: &'src_data mut [u8],
subservice: Subservice, subservice: Subservice,
time_stamp: &'a [u8], time_stamp: &'time [u8],
event_id: impl EcssEnumeration, event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>, aux_data: Option<&'src_data [u8]>,
) -> Result<PusTmCreator, EcssTmtcError> { ) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
let mut src_data_len = event_id.size(); let mut src_data_len = event_id.size();
if let Some(aux_data) = aux_data { if let Some(aux_data) = aux_data {
src_data_len += aux_data.len(); src_data_len += aux_data.len();
} }
source_buffer_large_enough(buf.len(), src_data_len)?; source_buffer_large_enough(src_data_buf.len(), src_data_len)?;
let mut sp_header = SpHeader::tm_unseg(self.apid, 0, 0).unwrap(); let mut sp_header = SpHeader::tm_unseg(self.apid, 0, 0).unwrap();
let sec_header = PusTmSecondaryHeader::new( let sec_header =
5, PusTmSecondaryHeader::new(5, subservice.into(), 0, self.dest_id, Some(time_stamp));
subservice.into(),
self.msg_count,
self.dest_id,
Some(time_stamp),
);
let mut current_idx = 0; let mut current_idx = 0;
event_id event_id.write_to_be_bytes(&mut src_data_buf[0..event_id.size()])?;
.write_to_be_bytes(&mut buf[0..event_id.size()])
.map_err(PusError::ByteConversion)?;
current_idx += event_id.size(); current_idx += event_id.size();
if let Some(aux_data) = aux_data { if let Some(aux_data) = aux_data {
buf[current_idx..current_idx + aux_data.len()].copy_from_slice(aux_data); src_data_buf[current_idx..current_idx + aux_data.len()].copy_from_slice(aux_data);
current_idx += aux_data.len(); current_idx += aux_data.len();
} }
Ok(PusTmCreator::new( Ok(PusTmCreator::new(
&mut sp_header, &mut sp_header,
sec_header, sec_header,
&buf[0..current_idx], &src_data_buf[0..current_idx],
true, true,
)) ))
} }
@ -156,84 +137,95 @@ impl EventReporterBase {
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
mod alloc_mod { mod alloc_mod {
use super::*; use super::*;
use crate::ComponentId;
use alloc::vec; use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::cell::RefCell;
pub struct EventReporter { pub struct EventReporter {
source_data_buf: Vec<u8>, id: ComponentId,
pub reporter: EventReporterBase, // Use interior mutability pattern here. This is just an intermediate buffer to the PUS event packet
// generation.
source_data_buf: RefCell<Vec<u8>>,
pub report_creator: EventReportCreator,
} }
impl EventReporter { impl EventReporter {
pub fn new(apid: u16, max_event_id_and_aux_data_size: usize) -> Option<Self> { pub fn new(
let reporter = EventReporterBase::new(apid)?; id: ComponentId,
apid: u16,
max_event_id_and_aux_data_size: usize,
) -> Option<Self> {
let reporter = EventReportCreator::new(apid)?;
Some(Self { Some(Self {
source_data_buf: vec![0; max_event_id_and_aux_data_size], id,
reporter, source_data_buf: RefCell::new(vec![0; max_event_id_and_aux_data_size]),
report_creator: reporter,
}) })
} }
pub fn event_info( pub fn event_info(
&mut self, &self,
sender: &mut (impl EcssTmSenderCore + ?Sized), sender: &(impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8], time_stamp: &[u8],
event_id: impl EcssEnumeration, event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>, aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> { ) -> Result<(), EcssTmtcError> {
self.reporter.event_info( let mut mut_buf = self.source_data_buf.borrow_mut();
self.source_data_buf.as_mut_slice(), let tm_creator = self
sender, .report_creator
time_stamp, .event_info(mut_buf.as_mut_slice(), time_stamp, event_id, aux_data)
event_id, .map_err(PusError::ByteConversion)?;
aux_data, sender.send_tm(self.id, tm_creator.into())?;
) Ok(())
} }
pub fn event_low_severity( pub fn event_low_severity(
&mut self, &self,
sender: &mut (impl EcssTmSenderCore + ?Sized), sender: &(impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8], time_stamp: &[u8],
event_id: impl EcssEnumeration, event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>, aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> { ) -> Result<(), EcssTmtcError> {
self.reporter.event_low_severity( let mut mut_buf = self.source_data_buf.borrow_mut();
self.source_data_buf.as_mut_slice(), let tm_creator = self
sender, .report_creator
time_stamp, .event_low_severity(mut_buf.as_mut_slice(), time_stamp, event_id, aux_data)
event_id, .map_err(PusError::ByteConversion)?;
aux_data, sender.send_tm(self.id, tm_creator.into())?;
) Ok(())
} }
pub fn event_medium_severity( pub fn event_medium_severity(
&mut self, &self,
sender: &mut (impl EcssTmSenderCore + ?Sized), sender: &(impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8], time_stamp: &[u8],
event_id: impl EcssEnumeration, event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>, aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> { ) -> Result<(), EcssTmtcError> {
self.reporter.event_medium_severity( let mut mut_buf = self.source_data_buf.borrow_mut();
self.source_data_buf.as_mut_slice(), let tm_creator = self
sender, .report_creator
time_stamp, .event_medium_severity(mut_buf.as_mut_slice(), time_stamp, event_id, aux_data)
event_id, .map_err(PusError::ByteConversion)?;
aux_data, sender.send_tm(self.id, tm_creator.into())?;
) Ok(())
} }
pub fn event_high_severity( pub fn event_high_severity(
&mut self, &self,
sender: &mut (impl EcssTmSenderCore + ?Sized), sender: &(impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8], time_stamp: &[u8],
event_id: impl EcssEnumeration, event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>, aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> { ) -> Result<(), EcssTmtcError> {
self.reporter.event_high_severity( let mut mut_buf = self.source_data_buf.borrow_mut();
self.source_data_buf.as_mut_slice(), let tm_creator = self
sender, .report_creator
time_stamp, .event_high_severity(mut_buf.as_mut_slice(), time_stamp, event_id, aux_data)
event_id, .map_err(PusError::ByteConversion)?;
aux_data, sender.send_tm(self.id, tm_creator.into())?;
) Ok(())
} }
} }
} }
@ -243,7 +235,7 @@ mod tests {
use super::*; use super::*;
use crate::events::{EventU32, Severity}; use crate::events::{EventU32, Severity};
use crate::pus::tests::CommonTmInfo; use crate::pus::tests::CommonTmInfo;
use crate::pus::{EcssChannel, PusTmWrapper}; use crate::pus::{ChannelWithId, PusTmVariant};
use crate::ComponentId; use crate::ComponentId;
use spacepackets::ByteConversionError; use spacepackets::ByteConversionError;
use std::cell::RefCell; use std::cell::RefCell;
@ -268,19 +260,19 @@ mod tests {
pub service_queue: RefCell<VecDeque<TmInfo>>, pub service_queue: RefCell<VecDeque<TmInfo>>,
} }
impl EcssChannel for TestSender { impl ChannelWithId for TestSender {
fn id(&self) -> ComponentId { fn id(&self) -> ComponentId {
0 0
} }
} }
impl EcssTmSenderCore for TestSender { impl EcssTmSenderCore for TestSender {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> { fn send_tm(&self, sender_id: ComponentId, tm: PusTmVariant) -> Result<(), EcssTmtcError> {
match tm { match tm {
PusTmWrapper::InStore(_) => { PusTmVariant::InStore(_) => {
panic!("TestSender: unexpected call with address"); panic!("TestSender: unexpected call with address");
} }
PusTmWrapper::Direct(tm) => { PusTmVariant::Direct(tm) => {
assert!(!tm.source_data().is_empty()); assert!(!tm.source_data().is_empty());
let src_data = tm.source_data(); let src_data = tm.source_data();
assert!(src_data.len() >= 4); assert!(src_data.len() >= 4);
@ -348,7 +340,7 @@ mod tests {
error_data: Option<&[u8]>, error_data: Option<&[u8]>,
) { ) {
let mut sender = TestSender::default(); let mut sender = TestSender::default();
let reporter = EventReporter::new(EXAMPLE_APID, max_event_aux_data_buf); let reporter = EventReporter::new(0, EXAMPLE_APID, max_event_aux_data_buf);
assert!(reporter.is_some()); assert!(reporter.is_some());
let mut reporter = reporter.unwrap(); let mut reporter = reporter.unwrap();
let time_stamp_empty: [u8; 7] = [0; 7]; let time_stamp_empty: [u8; 7] = [0; 7];
@ -440,7 +432,7 @@ mod tests {
fn insufficient_buffer() { fn insufficient_buffer() {
let mut sender = TestSender::default(); let mut sender = TestSender::default();
for i in 0..3 { for i in 0..3 {
let reporter = EventReporter::new(EXAMPLE_APID, i); let reporter = EventReporter::new(0, EXAMPLE_APID, i);
assert!(reporter.is_some()); assert!(reporter.is_some());
let mut reporter = reporter.unwrap(); let mut reporter = reporter.unwrap();
check_buf_too_small(&mut reporter, &mut sender, i); check_buf_too_small(&mut reporter, &mut sender, i);

View File

@ -177,8 +177,8 @@ pub mod alloc_mod {
} }
pub fn generate_pus_event_tm_generic( pub fn generate_pus_event_tm_generic(
&mut self, &self,
sender: &mut (impl EcssTmSenderCore + ?Sized), sender: &(impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8], time_stamp: &[u8],
event: EV, event: EV,
aux_data: Option<&[u8]>, aux_data: Option<&[u8]>,
@ -239,8 +239,8 @@ pub mod alloc_mod {
} }
pub fn generate_pus_event_tm<Severity: HasSeverity>( pub fn generate_pus_event_tm<Severity: HasSeverity>(
&mut self, &self,
sender: &mut (impl EcssTmSenderCore + ?Sized), sender: &(impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8], time_stamp: &[u8],
event: EventU32TypedSev<Severity>, event: EventU32TypedSev<Severity>,
aux_data: Option<&[u8]>, aux_data: Option<&[u8]>,
@ -257,20 +257,26 @@ pub mod alloc_mod {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{events::SeverityInfo, pus::TmAsVecSenderWithMpsc}; use crate::events::SeverityInfo;
use crate::pus::PusTmAsVec;
use crate::request::UniqueApidTargetId;
use std::sync::mpsc::{self, TryRecvError}; use std::sync::mpsc::{self, TryRecvError};
const INFO_EVENT: EventU32TypedSev<SeverityInfo> = const INFO_EVENT: EventU32TypedSev<SeverityInfo> =
EventU32TypedSev::<SeverityInfo>::const_new(1, 0); EventU32TypedSev::<SeverityInfo>::const_new(1, 0);
const LOW_SEV_EVENT: EventU32 = EventU32::const_new(Severity::LOW, 1, 5); const LOW_SEV_EVENT: EventU32 = EventU32::const_new(Severity::LOW, 1, 5);
const EMPTY_STAMP: [u8; 7] = [0; 7]; const EMPTY_STAMP: [u8; 7] = [0; 7];
const TEST_APID: u16 = 0x02;
const TEST_ID: UniqueApidTargetId = UniqueApidTargetId::new(TEST_APID, 0x05);
fn create_basic_man_1() -> DefaultPusEventU32Dispatcher<()> { fn create_basic_man_1() -> DefaultPusEventU32Dispatcher<()> {
let reporter = EventReporter::new(0x02, 128).expect("Creating event repoter failed"); let reporter = EventReporter::new(TEST_ID.raw(), TEST_APID, 128)
.expect("Creating event repoter failed");
PusEventDispatcher::new_with_default_backend(reporter) PusEventDispatcher::new_with_default_backend(reporter)
} }
fn create_basic_man_2() -> DefaultPusEventU32Dispatcher<()> { fn create_basic_man_2() -> DefaultPusEventU32Dispatcher<()> {
let reporter = EventReporter::new(0x02, 128).expect("Creating event repoter failed"); let reporter = EventReporter::new(TEST_ID.raw(), TEST_APID, 128)
.expect("Creating event repoter failed");
let backend = DefaultPusEventMgmtBackend::default(); let backend = DefaultPusEventMgmtBackend::default();
PusEventDispatcher::new(reporter, backend) PusEventDispatcher::new(reporter, backend)
} }
@ -278,10 +284,9 @@ mod tests {
#[test] #[test]
fn test_basic() { fn test_basic() {
let mut event_man = create_basic_man_1(); let mut event_man = create_basic_man_1();
let (event_tx, event_rx) = mpsc::channel(); let (mut event_tx, event_rx) = mpsc::channel::<PusTmAsVec>();
let mut sender = TmAsVecSenderWithMpsc::new(0, "test_sender", event_tx);
let event_sent = event_man let event_sent = event_man
.generate_pus_event_tm(&mut sender, &EMPTY_STAMP, INFO_EVENT, None) .generate_pus_event_tm(&mut event_tx, &EMPTY_STAMP, INFO_EVENT, None)
.expect("Sending info event failed"); .expect("Sending info event failed");
assert!(event_sent); assert!(event_sent);
@ -292,13 +297,13 @@ mod tests {
#[test] #[test]
fn test_disable_event() { fn test_disable_event() {
let mut event_man = create_basic_man_2(); let mut event_man = create_basic_man_2();
let (event_tx, event_rx) = mpsc::channel(); let (event_tx, event_rx) = mpsc::channel::<PusTmAsVec>();
let mut sender = TmAsVecSenderWithMpsc::new(0, "test", event_tx); // let mut sender = TmAsVecSenderWithMpsc::new(0, "test", event_tx);
let res = event_man.disable_tm_for_event(&LOW_SEV_EVENT); let res = event_man.disable_tm_for_event(&LOW_SEV_EVENT);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap()); assert!(res.unwrap());
let mut event_sent = event_man let mut event_sent = event_man
.generate_pus_event_tm_generic(&mut sender, &EMPTY_STAMP, LOW_SEV_EVENT, None) .generate_pus_event_tm_generic(&event_tx, &EMPTY_STAMP, LOW_SEV_EVENT, None)
.expect("Sending low severity event failed"); .expect("Sending low severity event failed");
assert!(!event_sent); assert!(!event_sent);
let res = event_rx.try_recv(); let res = event_rx.try_recv();
@ -306,7 +311,7 @@ mod tests {
assert!(matches!(res.unwrap_err(), TryRecvError::Empty)); assert!(matches!(res.unwrap_err(), TryRecvError::Empty));
// Check that only the low severity event was disabled // Check that only the low severity event was disabled
event_sent = event_man event_sent = event_man
.generate_pus_event_tm(&mut sender, &EMPTY_STAMP, INFO_EVENT, None) .generate_pus_event_tm(&event_tx, &EMPTY_STAMP, INFO_EVENT, None)
.expect("Sending info event failed"); .expect("Sending info event failed");
assert!(event_sent); assert!(event_sent);
event_rx.try_recv().expect("No info event received"); event_rx.try_recv().expect("No info event received");
@ -315,8 +320,7 @@ mod tests {
#[test] #[test]
fn test_reenable_event() { fn test_reenable_event() {
let mut event_man = create_basic_man_1(); let mut event_man = create_basic_man_1();
let (event_tx, event_rx) = mpsc::channel(); let (event_tx, event_rx) = mpsc::channel::<PusTmAsVec>();
let mut sender = TmAsVecSenderWithMpsc::new(0, "test", event_tx);
let mut res = event_man.disable_tm_for_event_with_sev(&INFO_EVENT); let mut res = event_man.disable_tm_for_event_with_sev(&INFO_EVENT);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap()); assert!(res.unwrap());
@ -324,7 +328,7 @@ mod tests {
assert!(res.is_ok()); assert!(res.is_ok());
assert!(res.unwrap()); assert!(res.unwrap());
let event_sent = event_man let event_sent = event_man
.generate_pus_event_tm(&mut sender, &EMPTY_STAMP, INFO_EVENT, None) .generate_pus_event_tm(&event_tx, &EMPTY_STAMP, INFO_EVENT, None)
.expect("Sending info event failed"); .expect("Sending info event failed");
assert!(event_sent); assert!(event_sent);
event_rx.try_recv().expect("No info event received"); event_rx.try_recv().expect("No info event received");

View File

@ -13,7 +13,7 @@ use super::{
GenericRoutingError, PusServiceHelper, GenericRoutingError, PusServiceHelper,
}; };
pub struct PusService5EventHandler< pub struct PusEventServiceHandler<
TcReceiver: EcssTcReceiverCore, TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore, TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConverter,
@ -29,7 +29,7 @@ impl<
TmSender: EcssTmSenderCore, TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
> PusService5EventHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter> > PusEventServiceHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{ {
pub fn new( pub fn new(
service_helper: PusServiceHelper< service_helper: PusServiceHelper<
@ -83,7 +83,12 @@ impl<
.service_helper .service_helper
.common .common
.verif_reporter .verif_reporter
.start_success(ecss_tc_and_token.token, time_stamp) .start_success(
self.service_helper.common.id,
&self.service_helper.common.tm_sender,
ecss_tc_and_token.token,
time_stamp,
)
.map_err(|_| PartialPusHandlingError::Verification); .map_err(|_| PartialPusHandlingError::Verification);
let partial_error = start_token.clone().err(); let partial_error = start_token.clone().err();
let mut token: TcStateToken = ecss_tc_and_token.token.into(); let mut token: TcStateToken = ecss_tc_and_token.token.into();
@ -161,9 +166,9 @@ mod tests {
use crate::pus::event_man::EventRequest; use crate::pus::event_man::EventRequest;
use crate::pus::test_util::{PusTestHarness, SimplePusPacketHandler, TEST_APID}; use crate::pus::test_util::{PusTestHarness, SimplePusPacketHandler, TEST_APID};
use crate::pus::verification::{ use crate::pus::verification::{
RequestId, VerificationReporterWithSharedPoolMpscBoundedSender, RequestId, VerificationReporter, VerificationReportingProvider,
}; };
use crate::pus::{GenericConversionError, MpscTcReceiver, TmInSharedPoolSenderWithBoundedMpsc}; use crate::pus::{GenericConversionError, MpscTcReceiver, MpscTmInSharedPoolSenderBounded};
use crate::{ use crate::{
events::EventU32, events::EventU32,
pus::{ pus::{
@ -174,34 +179,48 @@ mod tests {
}, },
}; };
use super::PusService5EventHandler; use super::PusEventServiceHandler;
const TEST_EVENT_0: EventU32 = EventU32::const_new(crate::events::Severity::INFO, 5, 25); const TEST_EVENT_0: EventU32 = EventU32::const_new(crate::events::Severity::INFO, 5, 25);
struct Pus5HandlerWithStoreTester { struct Pus5HandlerWithStoreTester {
common: PusServiceHandlerWithSharedStoreCommon, common: PusServiceHandlerWithSharedStoreCommon,
handler: PusService5EventHandler< handler: PusEventServiceHandler<
MpscTcReceiver, MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc, MpscTmInSharedPoolSenderBounded,
EcssTcInSharedStoreConverter, EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporter,
>, >,
} }
impl Pus5HandlerWithStoreTester { impl Pus5HandlerWithStoreTester {
pub fn new(event_request_tx: Sender<EventRequestWithToken>) -> Self { pub fn new(event_request_tx: Sender<EventRequestWithToken>) -> Self {
let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new(); let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new(0);
Self { Self {
common, common,
handler: PusService5EventHandler::new(srv_handler, event_request_tx), handler: PusEventServiceHandler::new(srv_handler, event_request_tx),
} }
} }
} }
impl PusTestHarness for Pus5HandlerWithStoreTester { impl PusTestHarness for Pus5HandlerWithStoreTester {
fn init_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let init_token = self.handler.service_helper.verif_reporter_mut().add_tc(tc);
self.handler
.service_helper
.verif_reporter()
.acceptance_success(
self.handler.service_helper.id(),
self.handler.service_helper.tm_sender(),
init_token,
&[0; 7],
)
.expect("acceptance success failure")
}
delegate! { delegate! {
to self.common { to self.common {
fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>; fn send_tc(&self, token: &VerificationToken<TcStateAccepted>, tc: &PusTcCreator);
fn read_next_tm(&mut self) -> PusTmReader<'_>; fn read_next_tm(&mut self) -> PusTmReader<'_>;
fn check_no_tm_available(&self) -> bool; fn check_no_tm_available(&self) -> bool;
fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId); fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId);
@ -212,7 +231,7 @@ mod tests {
impl SimplePusPacketHandler for Pus5HandlerWithStoreTester { impl SimplePusPacketHandler for Pus5HandlerWithStoreTester {
fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> { fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
let time_stamp = cds::TimeProvider::new_with_u16_days(0, 0).to_vec().unwrap(); let time_stamp = cds::CdsTime::new_with_u16_days(0, 0).to_vec().unwrap();
self.handler.poll_and_handle_next_tc(&time_stamp) self.handler.poll_and_handle_next_tc(&time_stamp)
} }
} }
@ -230,7 +249,8 @@ mod tests {
.write_to_be_bytes(&mut app_data) .write_to_be_bytes(&mut app_data)
.expect("writing test event failed"); .expect("writing test event failed");
let ping_tc = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true); let ping_tc = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true);
let token = test_harness.send_tc(&ping_tc); let token = test_harness.init_verification(&ping_tc);
test_harness.send_tc(&token, &ping_tc);
let request_id = token.request_id(); let request_id = token.request_id();
test_harness.handle_one_tc().unwrap(); test_harness.handle_one_tc().unwrap();
test_harness.check_next_verification_tm(1, request_id); test_harness.check_next_verification_tm(1, request_id);
@ -287,7 +307,8 @@ mod tests {
let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap(); let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap();
let sec_header = PusTcSecondaryHeader::new_simple(5, 200); let sec_header = PusTcSecondaryHeader::new_simple(5, 200);
let ping_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true); let ping_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true);
test_harness.send_tc(&ping_tc); let token = test_harness.init_verification(&ping_tc);
test_harness.send_tc(&token, &ping_tc);
let result = test_harness.handle_one_tc(); let result = test_harness.handle_one_tc();
assert!(result.is_ok()); assert!(result.is_ok());
let result = result.unwrap(); let result = result.unwrap();
@ -306,7 +327,8 @@ mod tests {
let sec_header = let sec_header =
PusTcSecondaryHeader::new_simple(5, Subservice::TcEnableEventGeneration as u8); PusTcSecondaryHeader::new_simple(5, Subservice::TcEnableEventGeneration as u8);
let ping_tc = PusTcCreator::new(&mut sp_header, sec_header, &[0, 1, 2], true); let ping_tc = PusTcCreator::new(&mut sp_header, sec_header, &[0, 1, 2], true);
test_harness.send_tc(&ping_tc); let token = test_harness.init_verification(&ping_tc);
test_harness.send_tc(&token, &ping_tc);
let result = test_harness.handle_one_tc(); let result = test_harness.handle_one_tc();
assert!(result.is_err()); assert!(result.is_err());
let result = result.unwrap_err(); let result = result.unwrap_err();

View File

@ -5,7 +5,7 @@
use crate::pool::{StoreAddr, StoreError}; use crate::pool::{StoreAddr, StoreError};
use crate::pus::verification::{TcStateAccepted, TcStateToken, VerificationToken}; use crate::pus::verification::{TcStateAccepted, TcStateToken, VerificationToken};
use crate::queue::{GenericReceiveError, GenericSendError}; use crate::queue::{GenericReceiveError, GenericSendError};
use crate::request::{GenericMessage, RequestId}; use crate::request::{GenericMessage, MessageMetadata, RequestId};
use crate::ComponentId; use crate::ComponentId;
use core::fmt::{Display, Formatter}; use core::fmt::{Display, Formatter};
use core::time::Duration; use core::time::Duration;
@ -43,19 +43,19 @@ pub use std_mod::*;
use self::verification::VerificationReportingProvider; use self::verification::VerificationReportingProvider;
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum PusTmWrapper<'tm> { pub enum PusTmVariant<'time, 'src_data> {
InStore(StoreAddr), InStore(StoreAddr),
Direct(PusTmCreator<'tm>), Direct(PusTmCreator<'time, 'src_data>),
} }
impl From<StoreAddr> for PusTmWrapper<'_> { impl From<StoreAddr> for PusTmVariant<'_, '_> {
fn from(value: StoreAddr) -> Self { fn from(value: StoreAddr) -> Self {
Self::InStore(value) Self::InStore(value)
} }
} }
impl<'tm> From<PusTmCreator<'tm>> for PusTmWrapper<'tm> { impl<'time, 'src_data> From<PusTmCreator<'time, 'src_data>> for PusTmVariant<'time, 'src_data> {
fn from(value: PusTmCreator<'tm>) -> Self { fn from(value: PusTmCreator<'time, 'src_data>) -> Self {
Self::Direct(value) Self::Direct(value)
} }
} }
@ -142,7 +142,7 @@ impl Error for EcssTmtcError {
} }
} }
} }
pub trait EcssChannel: Send { pub trait ChannelWithId: Send {
/// Each sender can have an ID associated with it /// Each sender can have an ID associated with it
fn id(&self) -> ComponentId; fn id(&self) -> ComponentId;
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
@ -154,7 +154,7 @@ pub trait EcssChannel: Send {
/// ///
/// This sender object is responsible for sending PUS telemetry to a TM sink. /// This sender object is responsible for sending PUS telemetry to a TM sink.
pub trait EcssTmSenderCore: Send { pub trait EcssTmSenderCore: Send {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError>; fn send_tm(&self, source_id: ComponentId, tm: PusTmVariant) -> Result<(), EcssTmtcError>;
} }
/// Generic trait for a user supplied sender object. /// Generic trait for a user supplied sender object.
@ -165,6 +165,16 @@ pub trait EcssTcSenderCore {
fn send_tc(&self, tc: PusTcCreator, token: Option<TcStateToken>) -> Result<(), EcssTmtcError>; fn send_tc(&self, tc: PusTcCreator, token: Option<TcStateToken>) -> Result<(), EcssTmtcError>;
} }
/// Dummy object which can be useful for tests.
#[derive(Default)]
pub struct EcssTmDummySender {}
impl EcssTmSenderCore for EcssTmDummySender {
fn send_tm(&self, _source_id: ComponentId, _tm: PusTmVariant) -> Result<(), EcssTmtcError> {
Ok(())
}
}
/// A PUS telecommand packet can be stored in memory using different methods. Right now, /// A PUS telecommand packet can be stored in memory using different methods. Right now,
/// storage inside a pool structure like [crate::pool::StaticMemoryPool], and storage inside a /// storage inside a pool structure like [crate::pool::StaticMemoryPool], and storage inside a
/// `Vec<u8>` are supported. /// `Vec<u8>` are supported.
@ -259,7 +269,7 @@ impl From<StoreError> for TryRecvTmtcError {
} }
/// Generic trait for a user supplied receiver object. /// Generic trait for a user supplied receiver object.
pub trait EcssTcReceiverCore: EcssChannel { pub trait EcssTcReceiverCore {
fn recv_tc(&self) -> Result<EcssTcAndToken, TryRecvTmtcError>; fn recv_tc(&self) -> Result<EcssTcAndToken, TryRecvTmtcError>;
} }
@ -301,8 +311,7 @@ pub trait PusRequestRouter<Request> {
fn route( fn route(
&self, &self,
request_id: RequestId, requestor_info: MessageMetadata,
source_id: ComponentId,
target_id: ComponentId, target_id: ComponentId,
request: Request, request: Request,
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
@ -315,15 +324,17 @@ pub trait PusReplyHandler<ActiveRequestInfo: ActiveRequestProvider, ReplyType> {
/// is finished. A finished PUS request will be removed from the active request map. /// is finished. A finished PUS request will be removed from the active request map.
fn handle_reply( fn handle_reply(
&mut self, &mut self,
caller_id: ComponentId,
reply: &GenericMessage<ReplyType>, reply: &GenericMessage<ReplyType>,
active_request: &ActiveRequestInfo, active_request: &ActiveRequestInfo,
tm_sender: &impl EcssTmSenderCore,
verification_handler: &impl VerificationReportingProvider, verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8], time_stamp: &[u8],
tm_sender: &impl EcssTmSenderCore,
) -> Result<bool, Self::Error>; ) -> Result<bool, Self::Error>;
fn handle_unrequested_reply( fn handle_unrequested_reply(
&mut self, &mut self,
caller_id: ComponentId,
reply: &GenericMessage<ReplyType>, reply: &GenericMessage<ReplyType>,
tm_sender: &impl EcssTmSenderCore, tm_sender: &impl EcssTmSenderCore,
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
@ -331,10 +342,11 @@ pub trait PusReplyHandler<ActiveRequestInfo: ActiveRequestProvider, ReplyType> {
/// Handle the timeout of an active request. /// Handle the timeout of an active request.
fn handle_request_timeout( fn handle_request_timeout(
&mut self, &mut self,
caller_id: ComponentId,
active_request: &ActiveRequestInfo, active_request: &ActiveRequestInfo,
tm_sender: &impl EcssTmSenderCore,
verification_handler: &impl VerificationReportingProvider, verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8], time_stamp: &[u8],
tm_sender: &impl EcssTmSenderCore,
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
} }
@ -445,10 +457,12 @@ pub mod alloc_mod {
type Error; type Error;
fn convert( fn convert(
&mut self, &mut self,
caller_id: ComponentId,
token: VerificationToken<TcStateAccepted>, token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader, tc: &PusTcReader,
time_stamp: &[u8], tm_sender: &(impl EcssTmSenderCore + ?Sized),
verif_reporter: &impl VerificationReportingProvider, verif_reporter: &impl VerificationReportingProvider,
time_stamp: &[u8],
) -> Result<(ActiveRequestInfo, Request), Self::Error>; ) -> Result<(ActiveRequestInfo, Request), Self::Error>;
} }
@ -647,8 +661,8 @@ pub mod std_mod {
}; };
use crate::pus::verification::{TcStateAccepted, VerificationToken}; use crate::pus::verification::{TcStateAccepted, VerificationToken};
use crate::pus::{ use crate::pus::{
EcssChannel, EcssTcAndToken, EcssTcReceiverCore, EcssTmSenderCore, EcssTmtcError, EcssTcAndToken, EcssTcReceiverCore, EcssTmSenderCore, EcssTmtcError, GenericReceiveError,
GenericReceiveError, GenericSendError, PusTmWrapper, TryRecvTmtcError, GenericSendError, PusTmVariant, TryRecvTmtcError,
}; };
use crate::tmtc::tm_helper::SharedTmPool; use crate::tmtc::tm_helper::SharedTmPool;
use crate::ComponentId; use crate::ComponentId;
@ -670,54 +684,82 @@ pub mod std_mod {
use super::verification::{TcStateToken, VerificationReportingProvider}; use super::verification::{TcStateToken, VerificationReportingProvider};
use super::{AcceptedEcssTcAndToken, ActiveRequestProvider, TcInMemory}; use super::{AcceptedEcssTcAndToken, ActiveRequestProvider, TcInMemory};
#[derive(Debug)]
pub struct PusTmInPool {
pub source_id: ComponentId,
pub store_addr: StoreAddr,
}
impl From<mpsc::SendError<StoreAddr>> for EcssTmtcError { impl From<mpsc::SendError<StoreAddr>> for EcssTmtcError {
fn from(_: mpsc::SendError<StoreAddr>) -> Self { fn from(_: mpsc::SendError<StoreAddr>) -> Self {
Self::Send(GenericSendError::RxDisconnected) Self::Send(GenericSendError::RxDisconnected)
} }
} }
impl EcssTmSenderCore for mpsc::Sender<StoreAddr> { impl EcssTmSenderCore for mpsc::Sender<PusTmInPool> {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> { fn send_tm(&self, source_id: ComponentId, tm: PusTmVariant) -> Result<(), EcssTmtcError> {
match tm { match tm {
PusTmWrapper::InStore(addr) => self PusTmVariant::InStore(store_addr) => self
.send(addr) .send(PusTmInPool {
source_id,
store_addr,
})
.map_err(|_| GenericSendError::RxDisconnected)?, .map_err(|_| GenericSendError::RxDisconnected)?,
PusTmWrapper::Direct(_) => return Err(EcssTmtcError::CantSendDirectTm), PusTmVariant::Direct(_) => return Err(EcssTmtcError::CantSendDirectTm),
}; };
Ok(()) Ok(())
} }
} }
impl EcssTmSenderCore for mpsc::SyncSender<StoreAddr> { impl EcssTmSenderCore for mpsc::SyncSender<PusTmInPool> {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> { fn send_tm(&self, source_id: ComponentId, tm: PusTmVariant) -> Result<(), EcssTmtcError> {
match tm { match tm {
PusTmWrapper::InStore(addr) => self PusTmVariant::InStore(store_addr) => self
.try_send(addr) .try_send(PusTmInPool {
source_id,
store_addr,
})
.map_err(|e| EcssTmtcError::Send(e.into()))?, .map_err(|e| EcssTmtcError::Send(e.into()))?,
PusTmWrapper::Direct(_) => return Err(EcssTmtcError::CantSendDirectTm), PusTmVariant::Direct(_) => return Err(EcssTmtcError::CantSendDirectTm),
}; };
Ok(()) Ok(())
} }
} }
impl EcssTmSenderCore for mpsc::Sender<Vec<u8>> { #[derive(Debug)]
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> { pub struct PusTmAsVec {
pub source_id: ComponentId,
pub packet: Vec<u8>,
}
pub type MpscTmAsVecSender = mpsc::Sender<PusTmAsVec>;
impl EcssTmSenderCore for MpscTmAsVecSender {
fn send_tm(&self, source_id: ComponentId, tm: PusTmVariant) -> Result<(), EcssTmtcError> {
match tm { match tm {
PusTmWrapper::InStore(addr) => return Err(EcssTmtcError::CantSendAddr(addr)), PusTmVariant::InStore(addr) => return Err(EcssTmtcError::CantSendAddr(addr)),
PusTmWrapper::Direct(tm) => self PusTmVariant::Direct(tm) => self
.send(tm.to_vec()?) .send(PusTmAsVec {
source_id,
packet: tm.to_vec()?,
})
.map_err(|e| EcssTmtcError::Send(e.into()))?, .map_err(|e| EcssTmtcError::Send(e.into()))?,
}; };
Ok(()) Ok(())
} }
} }
impl EcssTmSenderCore for mpsc::SyncSender<Vec<u8>> { pub type MpscTmAsVecSenderBounded = mpsc::SyncSender<PusTmAsVec>;
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
impl EcssTmSenderCore for MpscTmAsVecSenderBounded {
fn send_tm(&self, source_id: ComponentId, tm: PusTmVariant) -> Result<(), EcssTmtcError> {
match tm { match tm {
PusTmWrapper::InStore(addr) => return Err(EcssTmtcError::CantSendAddr(addr)), PusTmVariant::InStore(addr) => return Err(EcssTmtcError::CantSendAddr(addr)),
PusTmWrapper::Direct(tm) => self PusTmVariant::Direct(tm) => self
.send(tm.to_vec()?) .send(PusTmAsVec {
source_id,
packet: tm.to_vec()?,
})
.map_err(|e| EcssTmtcError::Send(e.into()))?, .map_err(|e| EcssTmtcError::Send(e.into()))?,
}; };
Ok(()) Ok(())
@ -725,67 +767,52 @@ pub mod std_mod {
} }
#[derive(Clone)] #[derive(Clone)]
pub struct TmInSharedPoolSenderWithId<Sender: EcssTmSenderCore> { pub struct TmInSharedPoolSender<Sender: EcssTmSenderCore> {
channel_id: ComponentId,
name: &'static str,
shared_tm_store: SharedTmPool, shared_tm_store: SharedTmPool,
sender: Sender, sender: Sender,
} }
impl<Sender: EcssTmSenderCore> EcssChannel for TmInSharedPoolSenderWithId<Sender> { impl<Sender: EcssTmSenderCore> TmInSharedPoolSender<Sender> {
fn id(&self) -> ComponentId { pub fn send_direct_tm(
self.channel_id &self,
} source_id: ComponentId,
tm: PusTmCreator,
fn name(&self) -> &'static str { ) -> Result<(), EcssTmtcError> {
self.name
}
}
impl<Sender: EcssTmSenderCore> TmInSharedPoolSenderWithId<Sender> {
pub fn send_direct_tm(&self, tm: PusTmCreator) -> Result<(), EcssTmtcError> {
let addr = self.shared_tm_store.add_pus_tm(&tm)?; let addr = self.shared_tm_store.add_pus_tm(&tm)?;
self.sender.send_tm(PusTmWrapper::InStore(addr)) self.sender.send_tm(source_id, PusTmVariant::InStore(addr))
} }
} }
impl<Sender: EcssTmSenderCore> EcssTmSenderCore for TmInSharedPoolSenderWithId<Sender> { impl<Sender: EcssTmSenderCore> EcssTmSenderCore for TmInSharedPoolSender<Sender> {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> { fn send_tm(&self, source_id: ComponentId, tm: PusTmVariant) -> Result<(), EcssTmtcError> {
if let PusTmWrapper::Direct(tm) = tm { if let PusTmVariant::Direct(tm) = tm {
return self.send_direct_tm(tm); return self.send_direct_tm(source_id, tm);
} }
self.sender.send_tm(tm) self.sender.send_tm(source_id, tm)
} }
} }
impl<Sender: EcssTmSenderCore> TmInSharedPoolSenderWithId<Sender> { impl<Sender: EcssTmSenderCore> TmInSharedPoolSender<Sender> {
pub fn new( pub fn new(shared_tm_store: SharedTmPool, sender: Sender) -> Self {
id: ComponentId,
name: &'static str,
shared_tm_store: SharedTmPool,
sender: Sender,
) -> Self {
Self { Self {
channel_id: id,
name,
shared_tm_store, shared_tm_store,
sender, sender,
} }
} }
} }
pub type TmInSharedPoolSenderWithMpsc = TmInSharedPoolSenderWithId<mpsc::Sender<StoreAddr>>; pub type MpscTmInSharedPoolSender = TmInSharedPoolSender<mpsc::Sender<PusTmInPool>>;
pub type TmInSharedPoolSenderWithBoundedMpsc = pub type MpscTmInSharedPoolSenderBounded = TmInSharedPoolSender<mpsc::SyncSender<PusTmInPool>>;
TmInSharedPoolSenderWithId<mpsc::SyncSender<StoreAddr>>;
/*
/// This class can be used if frequent heap allocations during run-time are not an issue. /// This class can be used if frequent heap allocations during run-time are not an issue.
/// PUS TM packets will be sent around as [Vec]s. Please note that the current implementation /// PUS TM packets will be sent around as [Vec]s. Please note that the current implementation
/// of this class can not deal with store addresses, so it is assumed that is is always /// of this class can not deal with store addresses, so it is assumed that is is always
/// going to be called with direct packets. /// going to be called with direct packets.
#[derive(Clone)] #[derive(Clone)]
pub struct TmAsVecSenderWithId<Sender: EcssTmSenderCore> { pub struct TmAsVecSenderWithId<Sender: EcssTmSenderCore> {
id: ComponentId, // id: ComponentId,
name: &'static str, //name: &'static str,
sender: Sender, sender: Sender,
} }
@ -801,7 +828,7 @@ pub mod std_mod {
} }
} }
impl<Sender: EcssTmSenderCore> EcssChannel for TmAsVecSenderWithId<Sender> { impl<Sender: EcssTmSenderCore> ChannelWithId for TmAsVecSenderWithId<Sender> {
fn id(&self) -> ComponentId { fn id(&self) -> ComponentId {
self.id self.id
} }
@ -811,58 +838,34 @@ pub mod std_mod {
} }
impl<Sender: EcssTmSenderCore> EcssTmSenderCore for TmAsVecSenderWithId<Sender> { impl<Sender: EcssTmSenderCore> EcssTmSenderCore for TmAsVecSenderWithId<Sender> {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> { fn send_tm(&self, tm: PusTmVariant) -> Result<(), EcssTmtcError> {
self.sender.send_tm(tm) self.sender.send_tm(tm)
} }
} }
pub type TmAsVecSenderWithMpsc = TmAsVecSenderWithId<mpsc::Sender<Vec<u8>>>; pub type TmAsVecSenderWithMpsc = TmAsVecSenderWithId<mpsc::Sender<Vec<u8>>>;
pub type TmAsVecSenderWithBoundedMpsc = TmAsVecSenderWithId<mpsc::SyncSender<Vec<u8>>>; pub type TmAsVecSenderWithBoundedMpsc = TmAsVecSenderWithId<mpsc::SyncSender<Vec<u8>>>;
*/
pub struct MpscTcReceiver { pub type MpscTcReceiver = mpsc::Receiver<EcssTcAndToken>;
id: ComponentId,
name: &'static str,
receiver: mpsc::Receiver<EcssTcAndToken>,
}
impl EcssChannel for MpscTcReceiver {
fn id(&self) -> ComponentId {
self.id
}
fn name(&self) -> &'static str {
self.name
}
}
impl EcssTcReceiverCore for MpscTcReceiver { impl EcssTcReceiverCore for MpscTcReceiver {
fn recv_tc(&self) -> Result<EcssTcAndToken, TryRecvTmtcError> { fn recv_tc(&self) -> Result<EcssTcAndToken, TryRecvTmtcError> {
self.receiver.try_recv().map_err(|e| match e { self.try_recv().map_err(|e| match e {
TryRecvError::Empty => TryRecvTmtcError::Empty, TryRecvError::Empty => TryRecvTmtcError::Empty,
TryRecvError::Disconnected => TryRecvTmtcError::Tmtc(EcssTmtcError::from( TryRecvError::Disconnected => TryRecvTmtcError::Tmtc(EcssTmtcError::from(
GenericReceiveError::TxDisconnected(Some(self.id())), GenericReceiveError::TxDisconnected(None),
)), )),
}) })
} }
} }
impl MpscTcReceiver {
pub fn new(
id: ComponentId,
name: &'static str,
receiver: mpsc::Receiver<EcssTcAndToken>,
) -> Self {
Self { id, name, receiver }
}
}
#[cfg(feature = "crossbeam")] #[cfg(feature = "crossbeam")]
pub mod cb_mod { pub mod cb_mod {
use super::*; use super::*;
use crossbeam_channel as cb; use crossbeam_channel as cb;
pub type TmInSharedPoolSenderWithCrossbeam = pub type TmInSharedPoolSenderWithCrossbeam = TmInSharedPoolSender<cb::Sender<PusTmInPool>>;
TmInSharedPoolSenderWithId<cb::Sender<StoreAddr>>;
impl From<cb::SendError<StoreAddr>> for EcssTmtcError { impl From<cb::SendError<StoreAddr>> for EcssTmtcError {
fn from(_: cb::SendError<StoreAddr>) -> Self { fn from(_: cb::SendError<StoreAddr>) -> Self {
@ -881,65 +884,44 @@ pub mod std_mod {
} }
} }
impl EcssTmSenderCore for cb::Sender<StoreAddr> { impl EcssTmSenderCore for cb::Sender<PusTmInPool> {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> { fn send_tm(
&self,
source_id: ComponentId,
tm: PusTmVariant,
) -> Result<(), EcssTmtcError> {
match tm { match tm {
PusTmWrapper::InStore(addr) => self PusTmVariant::InStore(addr) => self
.try_send(addr) .try_send(PusTmInPool {
source_id,
store_addr: addr,
})
.map_err(|e| EcssTmtcError::Send(e.into()))?, .map_err(|e| EcssTmtcError::Send(e.into()))?,
PusTmWrapper::Direct(_) => return Err(EcssTmtcError::CantSendDirectTm), PusTmVariant::Direct(_) => return Err(EcssTmtcError::CantSendDirectTm),
}; };
Ok(()) Ok(())
} }
} }
impl EcssTmSenderCore for cb::Sender<Vec<u8>> { impl EcssTmSenderCore for cb::Sender<PusTmAsVec> {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> { fn send_tm(
&self,
source_id: ComponentId,
tm: PusTmVariant,
) -> Result<(), EcssTmtcError> {
match tm { match tm {
PusTmWrapper::InStore(addr) => return Err(EcssTmtcError::CantSendAddr(addr)), PusTmVariant::InStore(addr) => return Err(EcssTmtcError::CantSendAddr(addr)),
PusTmWrapper::Direct(tm) => self PusTmVariant::Direct(tm) => self
.send(tm.to_vec()?) .send(PusTmAsVec {
source_id,
packet: tm.to_vec()?,
})
.map_err(|e| EcssTmtcError::Send(e.into()))?, .map_err(|e| EcssTmtcError::Send(e.into()))?,
}; };
Ok(()) Ok(())
} }
} }
pub struct CrossbeamTcReceiver { pub type CrossbeamTcReceiver = cb::Receiver<EcssTcAndToken>;
id: ComponentId,
name: &'static str,
receiver: cb::Receiver<EcssTcAndToken>,
}
impl CrossbeamTcReceiver {
pub fn new(
id: ComponentId,
name: &'static str,
receiver: cb::Receiver<EcssTcAndToken>,
) -> Self {
Self { id, name, receiver }
}
}
impl EcssChannel for CrossbeamTcReceiver {
fn id(&self) -> ComponentId {
self.id
}
fn name(&self) -> &'static str {
self.name
}
}
impl EcssTcReceiverCore for CrossbeamTcReceiver {
fn recv_tc(&self) -> Result<EcssTcAndToken, TryRecvTmtcError> {
self.receiver.try_recv().map_err(|e| match e {
cb::TryRecvError::Empty => TryRecvTmtcError::Empty,
cb::TryRecvError::Disconnected => TryRecvTmtcError::Tmtc(EcssTmtcError::from(
GenericReceiveError::TxDisconnected(Some(self.id())),
)),
})
}
}
} }
/// This is a high-level handler for the generic PUS services which need to convert PUS /// This is a high-level handler for the generic PUS services which need to convert PUS
@ -1294,9 +1276,9 @@ pub mod std_mod {
TmSender: EcssTmSenderCore, TmSender: EcssTmSenderCore,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
> { > {
pub id: ComponentId,
pub tc_receiver: TcReceiver, pub tc_receiver: TcReceiver,
pub tm_sender: TmSender, pub tm_sender: TmSender,
pub tm_apid: u16,
pub verif_reporter: VerificationReporter, pub verif_reporter: VerificationReporter,
} }
@ -1327,23 +1309,31 @@ pub mod std_mod {
> PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter> > PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{ {
pub fn new( pub fn new(
id: ComponentId,
tc_receiver: TcReceiver, tc_receiver: TcReceiver,
tm_sender: TmSender, tm_sender: TmSender,
tm_apid: u16,
verification_handler: VerificationReporter, verification_handler: VerificationReporter,
tc_in_mem_converter: TcInMemConverter, tc_in_mem_converter: TcInMemConverter,
) -> Self { ) -> Self {
Self { Self {
common: PusServiceBase { common: PusServiceBase {
id,
tc_receiver, tc_receiver,
tm_sender, tm_sender,
tm_apid,
verif_reporter: verification_handler, verif_reporter: verification_handler,
}, },
tc_in_mem_converter, tc_in_mem_converter,
} }
} }
pub fn id(&self) -> ComponentId {
self.common.id
}
pub fn tm_sender(&self) -> &TmSender {
&self.common.tm_sender
}
/// This function can be used to poll the internal [EcssTcReceiverCore] object for the next /// This function can be used to poll the internal [EcssTcReceiverCore] object for the next
/// telecommand packet. It will return `Ok(None)` if there are not packets available. /// telecommand packet. It will return `Ok(None)` if there are not packets available.
/// In any other case, it will perform the acceptance of the ECSS TC packet using the /// In any other case, it will perform the acceptance of the ECSS TC packet using the
@ -1378,6 +1368,9 @@ pub mod std_mod {
pub fn verif_reporter(&self) -> &VerificationReporter { pub fn verif_reporter(&self) -> &VerificationReporter {
&self.common.verif_reporter &self.common.verif_reporter
} }
pub fn verif_reporter_mut(&mut self) -> &mut VerificationReporter {
&mut self.common.verif_reporter
}
pub fn tc_in_mem_converter(&self) -> &TcInMemConverter { pub fn tc_in_mem_converter(&self) -> &TcInMemConverter {
&self.tc_in_mem_converter &self.tc_in_mem_converter
@ -1388,50 +1381,47 @@ pub mod std_mod {
} }
} }
pub type PusServiceHelperDynWithMpsc<TcInMemConverter, VerificationReporter> = PusServiceHelper< pub type PusServiceHelperDynWithMpsc<TcInMemConverter, VerificationReporter> =
MpscTcReceiver, PusServiceHelper<MpscTcReceiver, MpscTmAsVecSender, TcInMemConverter, VerificationReporter>;
TmAsVecSenderWithMpsc,
TcInMemConverter,
VerificationReporter,
>;
pub type PusServiceHelperDynWithBoundedMpsc<TcInMemConverter, VerificationReporter> = pub type PusServiceHelperDynWithBoundedMpsc<TcInMemConverter, VerificationReporter> =
PusServiceHelper< PusServiceHelper<
MpscTcReceiver, MpscTcReceiver,
TmAsVecSenderWithBoundedMpsc, MpscTmAsVecSenderBounded,
TcInMemConverter, TcInMemConverter,
VerificationReporter, VerificationReporter,
>; >;
pub type PusServiceHelperStaticWithMpsc<TcInMemConverter, VerificationReporter> = pub type PusServiceHelperStaticWithMpsc<TcInMemConverter, VerificationReporter> =
PusServiceHelper< PusServiceHelper<
MpscTcReceiver, MpscTcReceiver,
TmInSharedPoolSenderWithMpsc, MpscTmInSharedPoolSender,
TcInMemConverter, TcInMemConverter,
VerificationReporter, VerificationReporter,
>; >;
pub type PusServiceHelperStaticWithBoundedMpsc<TcInMemConverter, VerificationReporter> = pub type PusServiceHelperStaticWithBoundedMpsc<TcInMemConverter, VerificationReporter> =
PusServiceHelper< PusServiceHelper<
MpscTcReceiver, MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc, MpscTmInSharedPoolSenderBounded,
TcInMemConverter, TcInMemConverter,
VerificationReporter, VerificationReporter,
>; >;
} }
pub(crate) fn source_buffer_large_enough(cap: usize, len: usize) -> Result<(), EcssTmtcError> { pub(crate) fn source_buffer_large_enough(
cap: usize,
len: usize,
) -> Result<(), ByteConversionError> {
if len > cap { if len > cap {
return Err( return Err(ByteConversionError::ToSliceTooSmall {
PusError::ByteConversion(ByteConversionError::ToSliceTooSmall { found: cap,
found: cap, expected: len,
expected: len, });
})
.into(),
);
} }
Ok(()) Ok(())
} }
#[cfg(any(feature = "test_util", test))] #[cfg(any(feature = "test_util", test))]
pub mod test_util { pub mod test_util {
use crate::request::UniqueApidTargetId;
use spacepackets::ecss::{tc::PusTcCreator, tm::PusTmReader}; use spacepackets::ecss::{tc::PusTcCreator, tm::PusTmReader};
use super::{ use super::{
@ -1440,9 +1430,13 @@ pub mod test_util {
}; };
pub const TEST_APID: u16 = 0x101; pub const TEST_APID: u16 = 0x101;
pub const TEST_UNIQUE_ID: u32 = 0x05;
pub const TEST_COMPONENT_ID: UniqueApidTargetId =
UniqueApidTargetId::new(TEST_APID, TEST_UNIQUE_ID);
pub trait PusTestHarness { pub trait PusTestHarness {
fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>; fn init_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>;
fn send_tc(&self, token: &VerificationToken<TcStateAccepted>, tc: &PusTcCreator);
fn read_next_tm(&mut self) -> PusTmReader<'_>; fn read_next_tm(&mut self) -> PusTmReader<'_>;
fn check_no_tm_available(&self) -> bool; fn check_no_tm_available(&self) -> bool;
fn check_next_verification_tm( fn check_next_verification_tm(
@ -1471,22 +1465,16 @@ pub mod tests {
use spacepackets::ecss::{PusPacket, WritablePusPacket}; use spacepackets::ecss::{PusPacket, WritablePusPacket};
use spacepackets::CcsdsPacket; use spacepackets::CcsdsPacket;
use crate::pool::{ use crate::pool::{PoolProvider, SharedStaticMemoryPool, StaticMemoryPool, StaticPoolConfig};
PoolProvider, SharedStaticMemoryPool, StaticMemoryPool, StaticPoolConfig, StoreAddr, use crate::pus::verification::{RequestId, VerificationReporter};
};
use crate::pus::verification::RequestId;
use crate::tmtc::tm_helper::SharedTmPool; use crate::tmtc::tm_helper::SharedTmPool;
use crate::ComponentId; use crate::ComponentId;
use super::test_util::TEST_APID; use super::test_util::{TEST_APID, TEST_COMPONENT_ID};
use super::verification::std_mod::{ use super::verification::test_util::TestVerificationReporter;
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender,
};
use super::verification::test_util::{SharedVerificationMap, TestVerificationReporter};
use super::verification::{ use super::verification::{
TcStateAccepted, VerificationReporterCfg, VerificationReporterWithSender, TcStateAccepted, VerificationReporterCfg, VerificationReportingProvider, VerificationToken,
VerificationReportingProvider, VerificationToken,
}; };
use super::*; use super::*;
@ -1515,20 +1503,19 @@ pub mod tests {
/// Common fields for a PUS service test harness. /// Common fields for a PUS service test harness.
pub struct PusServiceHandlerWithSharedStoreCommon { pub struct PusServiceHandlerWithSharedStoreCommon {
pus_buf: [u8; 2048], pus_buf: RefCell<[u8; 2048]>,
tm_buf: [u8; 2048], tm_buf: [u8; 2048],
tc_pool: SharedStaticMemoryPool, tc_pool: SharedStaticMemoryPool,
tm_pool: SharedTmPool, tm_pool: SharedTmPool,
tc_sender: mpsc::SyncSender<EcssTcAndToken>, tc_sender: mpsc::SyncSender<EcssTcAndToken>,
tm_receiver: mpsc::Receiver<StoreAddr>, tm_receiver: mpsc::Receiver<PusTmInPool>,
verification_handler: VerificationReporterWithSharedPoolMpscBoundedSender,
} }
pub type PusServiceHelperStatic = PusServiceHelper< pub type PusServiceHelperStatic = PusServiceHelper<
MpscTcReceiver, MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc, MpscTmInSharedPoolSenderBounded,
EcssTcInSharedStoreConverter, EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporter,
>; >;
impl PusServiceHandlerWithSharedStoreCommon { impl PusServiceHandlerWithSharedStoreCommon {
@ -1536,7 +1523,7 @@ pub mod tests {
/// [PusServiceHandler] which might be required for a specific PUS service handler. /// [PusServiceHandler] which might be required for a specific PUS service handler.
/// ///
/// The PUS service handler is instantiated with a [EcssTcInStoreConverter]. /// The PUS service handler is instantiated with a [EcssTcInStoreConverter].
pub fn new() -> (Self, PusServiceHelperStatic) { pub fn new(id: ComponentId) -> (Self, PusServiceHelperStatic) {
let pool_cfg = StaticPoolConfig::new(alloc::vec![(16, 16), (8, 32), (4, 64)], false); let pool_cfg = StaticPoolConfig::new(alloc::vec![(16, 16), (8, 32), (4, 64)], false);
let tc_pool = StaticMemoryPool::new(pool_cfg.clone()); let tc_pool = StaticMemoryPool::new(pool_cfg.clone());
let tm_pool = StaticMemoryPool::new(pool_cfg); let tm_pool = StaticMemoryPool::new(pool_cfg);
@ -1545,62 +1532,47 @@ pub mod tests {
let (test_srv_tc_tx, test_srv_tc_rx) = mpsc::sync_channel(10); let (test_srv_tc_tx, test_srv_tc_rx) = mpsc::sync_channel(10);
let (tm_tx, tm_rx) = mpsc::sync_channel(10); let (tm_tx, tm_rx) = mpsc::sync_channel(10);
let verif_sender = TmInSharedPoolSenderWithBoundedMpsc::new(
0,
"verif_sender",
shared_tm_pool.clone(),
tm_tx.clone(),
);
let verif_cfg = VerificationReporterCfg::new(TEST_APID, 1, 2, 8).unwrap(); let verif_cfg = VerificationReporterCfg::new(TEST_APID, 1, 2, 8).unwrap();
let verification_handler = let verification_handler = VerificationReporter::new(&verif_cfg);
VerificationReporterWithSharedPoolMpscBoundedSender::new(&verif_cfg, verif_sender); let test_srv_tm_sender = TmInSharedPoolSender::new(shared_tm_pool.clone(), tm_tx);
let test_srv_tm_sender =
TmInSharedPoolSenderWithId::new(0, "TEST_SENDER", shared_tm_pool.clone(), tm_tx);
let test_srv_tc_receiver = MpscTcReceiver::new(0, "TEST_RECEIVER", test_srv_tc_rx);
let in_store_converter = let in_store_converter =
EcssTcInSharedStoreConverter::new(shared_tc_pool.clone(), 2048); EcssTcInSharedStoreConverter::new(shared_tc_pool.clone(), 2048);
( (
Self { Self {
pus_buf: [0; 2048], pus_buf: RefCell::new([0; 2048]),
tm_buf: [0; 2048], tm_buf: [0; 2048],
tc_pool: shared_tc_pool, tc_pool: shared_tc_pool,
tm_pool: shared_tm_pool, tm_pool: shared_tm_pool,
tc_sender: test_srv_tc_tx, tc_sender: test_srv_tc_tx,
tm_receiver: tm_rx, tm_receiver: tm_rx,
verification_handler: verification_handler.clone(),
}, },
PusServiceHelper::new( PusServiceHelper::new(
test_srv_tc_receiver, id,
test_srv_tc_rx,
test_srv_tm_sender, test_srv_tm_sender,
TEST_APID,
verification_handler, verification_handler,
in_store_converter, in_store_converter,
), ),
) )
} }
pub fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> { pub fn send_tc(&self, token: &VerificationToken<TcStateAccepted>, tc: &PusTcCreator) {
let token = self.verification_handler.add_tc(tc); let mut mut_buf = self.pus_buf.borrow_mut();
let token = self let tc_size = tc.write_to_bytes(mut_buf.as_mut_slice()).unwrap();
.verification_handler
.acceptance_success(token, &[0; 7])
.unwrap();
let tc_size = tc.write_to_bytes(&mut self.pus_buf).unwrap();
let mut tc_pool = self.tc_pool.write().unwrap(); let mut tc_pool = self.tc_pool.write().unwrap();
let addr = tc_pool.add(&self.pus_buf[..tc_size]).unwrap(); let addr = tc_pool.add(&mut_buf[..tc_size]).unwrap();
drop(tc_pool); drop(tc_pool);
// Send accepted TC to test service handler. // Send accepted TC to test service handler.
self.tc_sender self.tc_sender
.send(EcssTcAndToken::new(addr, token)) .send(EcssTcAndToken::new(addr, *token))
.expect("sending tc failed"); .expect("sending tc failed");
token
} }
pub fn read_next_tm(&mut self) -> PusTmReader<'_> { pub fn read_next_tm(&mut self) -> PusTmReader<'_> {
let next_msg = self.tm_receiver.try_recv(); let next_msg = self.tm_receiver.try_recv();
assert!(next_msg.is_ok()); assert!(next_msg.is_ok());
let tm_addr = next_msg.unwrap(); let tm_in_pool = next_msg.unwrap();
let tm_pool = self.tm_pool.0.read().unwrap(); let tm_pool = self.tm_pool.0.read().unwrap();
let tm_raw = tm_pool.read_as_vec(&tm_addr).unwrap(); let tm_raw = tm_pool.read_as_vec(&tm_in_pool.store_addr).unwrap();
self.tm_buf[0..tm_raw.len()].copy_from_slice(&tm_raw); self.tm_buf[0..tm_raw.len()].copy_from_slice(&tm_raw);
PusTmReader::new(&self.tm_buf, 7).unwrap().0 PusTmReader::new(&self.tm_buf, 7).unwrap().0
} }
@ -1616,9 +1588,9 @@ pub mod tests {
pub fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId) { pub fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId) {
let next_msg = self.tm_receiver.try_recv(); let next_msg = self.tm_receiver.try_recv();
assert!(next_msg.is_ok()); assert!(next_msg.is_ok());
let tm_addr = next_msg.unwrap(); let tm_in_pool = next_msg.unwrap();
let tm_pool = self.tm_pool.0.read().unwrap(); let tm_pool = self.tm_pool.0.read().unwrap();
let tm_raw = tm_pool.read_as_vec(&tm_addr).unwrap(); let tm_raw = tm_pool.read_as_vec(&tm_in_pool.store_addr).unwrap();
let tm = PusTmReader::new(&tm_raw, 7).unwrap().0; let tm = PusTmReader::new(&tm_raw, 7).unwrap().0;
assert_eq!(PusPacket::service(&tm), 1); assert_eq!(PusPacket::service(&tm), 1);
assert_eq!(PusPacket::subservice(&tm), subservice); assert_eq!(PusPacket::subservice(&tm), subservice);
@ -1629,56 +1601,49 @@ pub mod tests {
} }
} }
pub struct PusServiceHandlerWithVecCommon<VerificationReporter: VerificationReportingProvider> { pub struct PusServiceHandlerWithVecCommon {
current_tm: Option<alloc::vec::Vec<u8>>, current_tm: Option<Vec<u8>>,
tc_sender: mpsc::Sender<EcssTcAndToken>, tc_sender: mpsc::Sender<EcssTcAndToken>,
tm_receiver: mpsc::Receiver<alloc::vec::Vec<u8>>, tm_receiver: mpsc::Receiver<PusTmAsVec>,
pub verification_handler: VerificationReporter,
} }
pub type PusServiceHelperDynamic = PusServiceHelper< pub type PusServiceHelperDynamic = PusServiceHelper<
MpscTcReceiver, MpscTcReceiver,
TmAsVecSenderWithMpsc, MpscTmAsVecSender,
EcssTcInVecConverter, EcssTcInVecConverter,
VerificationReporterWithVecMpscSender, TestVerificationReporter,
>; >;
impl PusServiceHandlerWithVecCommon<VerificationReporterWithVecMpscSender> { impl PusServiceHandlerWithVecCommon {
pub fn new_with_standard_verif_reporter() -> (Self, PusServiceHelperDynamic) { pub fn new_with_standard_verif_reporter(
id: ComponentId,
) -> (Self, PusServiceHelperDynamic) {
let (test_srv_tc_tx, test_srv_tc_rx) = mpsc::channel(); let (test_srv_tc_tx, test_srv_tc_rx) = mpsc::channel();
let (tm_tx, tm_rx) = mpsc::channel(); let (tm_tx, tm_rx) = mpsc::channel();
let verif_sender = TmAsVecSenderWithId::new(0, "verififcatio-sender", tm_tx.clone());
let verif_cfg = VerificationReporterCfg::new(TEST_APID, 1, 2, 8).unwrap();
let verification_handler =
VerificationReporterWithSender::new(&verif_cfg, verif_sender);
let test_srv_tm_sender = TmAsVecSenderWithId::new(0, "test-sender", tm_tx);
let test_srv_tc_receiver = MpscTcReceiver::new(0, "test-receiver", test_srv_tc_rx);
let in_store_converter = EcssTcInVecConverter::default(); let in_store_converter = EcssTcInVecConverter::default();
( (
Self { Self {
current_tm: None, current_tm: None,
tc_sender: test_srv_tc_tx, tc_sender: test_srv_tc_tx,
tm_receiver: tm_rx, tm_receiver: tm_rx,
verification_handler: verification_handler.clone(),
}, },
PusServiceHelper::new( PusServiceHelper::new(
test_srv_tc_receiver, id,
test_srv_tm_sender, test_srv_tc_rx,
TEST_APID, tm_tx,
verification_handler, TestVerificationReporter::default(),
in_store_converter, in_store_converter,
), ),
) )
} }
} }
impl PusServiceHandlerWithVecCommon<TestVerificationReporter> { impl PusServiceHandlerWithVecCommon {
pub fn new_with_test_verif_sender() -> ( pub fn new_with_test_verif_sender() -> (
Self, Self,
PusServiceHelper< PusServiceHelper<
MpscTcReceiver, MpscTcReceiver,
TmAsVecSenderWithMpsc, MpscTmAsVecSender,
EcssTcInVecConverter, EcssTcInVecConverter,
TestVerificationReporter, TestVerificationReporter,
>, >,
@ -1686,22 +1651,19 @@ pub mod tests {
let (test_srv_tc_tx, test_srv_tc_rx) = mpsc::channel(); let (test_srv_tc_tx, test_srv_tc_rx) = mpsc::channel();
let (tm_tx, tm_rx) = mpsc::channel(); let (tm_tx, tm_rx) = mpsc::channel();
let test_srv_tm_sender = TmAsVecSenderWithId::new(0, "test-sender", tm_tx);
let test_srv_tc_receiver = MpscTcReceiver::new(0, "test-receiver", test_srv_tc_rx);
let in_store_converter = EcssTcInVecConverter::default(); let in_store_converter = EcssTcInVecConverter::default();
let shared_verif_map = SharedVerificationMap::default(); let verification_handler = TestVerificationReporter::default();
let verification_handler = TestVerificationReporter::new(shared_verif_map);
( (
Self { Self {
current_tm: None, current_tm: None,
tc_sender: test_srv_tc_tx, tc_sender: test_srv_tc_tx,
tm_receiver: tm_rx, tm_receiver: tm_rx,
verification_handler: verification_handler.clone(), //verification_handler: verification_handler.clone(),
}, },
PusServiceHelper::new( PusServiceHelper::new(
test_srv_tc_receiver, TEST_COMPONENT_ID.raw(),
test_srv_tm_sender, test_srv_tc_rx,
TEST_APID, tm_tx,
verification_handler, verification_handler,
in_store_converter, in_store_converter,
), ),
@ -1709,29 +1671,21 @@ pub mod tests {
} }
} }
impl<VerificationReporter: VerificationReportingProvider> impl PusServiceHandlerWithVecCommon {
PusServiceHandlerWithVecCommon<VerificationReporter> pub fn send_tc(&self, token: &VerificationToken<TcStateAccepted>, tc: &PusTcCreator) {
{
pub fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let token = self.verification_handler.add_tc(tc);
let token = self
.verification_handler
.acceptance_success(token, &[0; 7])
.unwrap();
// Send accepted TC to test service handler. // Send accepted TC to test service handler.
self.tc_sender self.tc_sender
.send(EcssTcAndToken::new( .send(EcssTcAndToken::new(
TcInMemory::Vec(tc.to_vec().expect("pus tc conversion to vec failed")), TcInMemory::Vec(tc.to_vec().expect("pus tc conversion to vec failed")),
token, *token,
)) ))
.expect("sending tc failed"); .expect("sending tc failed");
token
} }
pub fn read_next_tm(&mut self) -> PusTmReader<'_> { pub fn read_next_tm(&mut self) -> PusTmReader<'_> {
let next_msg = self.tm_receiver.try_recv(); let next_msg = self.tm_receiver.try_recv();
assert!(next_msg.is_ok()); assert!(next_msg.is_ok());
self.current_tm = Some(next_msg.unwrap()); self.current_tm = Some(next_msg.unwrap().packet);
PusTmReader::new(self.current_tm.as_ref().unwrap(), 7) PusTmReader::new(self.current_tm.as_ref().unwrap(), 7)
.unwrap() .unwrap()
.0 .0
@ -1749,7 +1703,7 @@ pub mod tests {
let next_msg = self.tm_receiver.try_recv(); let next_msg = self.tm_receiver.try_recv();
assert!(next_msg.is_ok()); assert!(next_msg.is_ok());
let next_msg = next_msg.unwrap(); let next_msg = next_msg.unwrap();
let tm = PusTmReader::new(next_msg.as_slice(), 7).unwrap().0; let tm = PusTmReader::new(next_msg.packet.as_slice(), 7).unwrap().0;
assert_eq!(PusPacket::service(&tm), 1); assert_eq!(PusPacket::service(&tm), 1);
assert_eq!(PusPacket::subservice(&tm), subservice); assert_eq!(PusPacket::subservice(&tm), subservice);
assert_eq!(tm.apid(), TEST_APID); assert_eq!(tm.apid(), TEST_APID);

View File

@ -31,139 +31,7 @@ pub mod alloc_mod {}
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
pub mod std_mod { pub mod std_mod {}
/*
use spacepackets::{
ecss::tm::{PusTmCreator, PusTmSecondaryHeader},
util::UnsignedEnum,
SpHeader,
};
pub trait ModeReplyHook: ReplyHandlerHook<ActivePusRequest, ModeReply> {
fn wrong_mode_result_code(&self) -> ResultU16;
fn can_not_reach_mode_result_code(&self) -> ResultU16;
}
/// Type definition for a PUS mode servicd reply handler which constrains the
/// [PusServiceReplyHandler] active request and reply generics to the [ActiveActionRequest] and
/// [ActionReplyPusWithIds] type.
pub type PusModeServiceReplyHandler<
VerificationReporter,
ActiveRequestMap,
UserHook,
TmSender,
> = PusServiceReplyHandler<
VerificationReporter,
ActiveRequestMap,
UserHook,
TmSender,
ActivePusRequest,
ModeReply,
>;
impl<
VerificationReporter: VerificationReportingProvider,
ActiveRequestMap: ActiveRequestMapProvider<ActivePusRequest>,
UserHook: ModeReplyHook,
TmSender: EcssTmSenderCore,
> PusModeServiceReplyHandler<VerificationReporter, ActiveRequestMap, UserHook, TmSender>
{
/// Helper method to register a recently routed action request.
pub fn add_routed_mode_request(
&mut self,
request_id: verification::RequestId,
target_id: TargetId,
token: VerificationToken<TcStateStarted>,
timeout: Duration,
) {
self.active_request_map.insert(
&request_id.into(),
ActivePusRequest {
target_id,
token,
start_time: self.current_time,
timeout,
},
)
}
/// Main handler function to handle all received action replies.
pub fn handle_mode_reply(
&mut self,
mode_reply_with_id: &GenericModeReply,
time_stamp: &[u8],
) -> Result<(), EcssTmtcError> {
let active_req = self.active_request_map.get(mode_reply_with_id.request_id);
if active_req.is_none() {
self.user_hook.handle_unexpected_reply(mode_reply_with_id);
return Ok(());
}
let active_req = active_req.unwrap().clone();
let remove_entry = match mode_reply_with_id.message {
ModeReply::ModeReply(reply) => {
reply.write_to_be_bytes(&mut self.tm_buf)?;
let req_id = verification::RequestId::from(mode_reply_with_id.request_id);
let mut sp_header = SpHeader::tm_unseg(
req_id.packet_id().apid(),
req_id.packet_seq_ctrl().seq_count(),
0,
)
.expect("space packet header creation error");
let sec_header = PusTmSecondaryHeader::new(
MODE_SERVICE_ID,
Subservice::TmModeReply as u8,
0,
0,
Some(time_stamp),
);
let pus_tm = PusTmCreator::new(&mut sp_header, sec_header, &self.tm_buf, true);
self.tm_sender.send_tm(PusTmWrapper::Direct(pus_tm))?;
self.verification_reporter
.completion_success(active_req.token, time_stamp)
.map_err(|e| e.0)?;
true
}
ModeReply::CantReachMode(reason) => {
let fail_data_len = reason.write_to_be_bytes(&mut self.tm_buf)?;
self.verification_reporter
.completion_failure(
active_req.token,
FailParams::new(
time_stamp,
&self.user_hook.can_not_reach_mode_result_code(),
&self.tm_buf[0..fail_data_len],
),
)
.map_err(|e| e.0)?;
true
}
ModeReply::WrongMode { expected, reached } => {
let expected_len = expected.write_to_be_bytes(&mut self.tm_buf)?;
let reached_len =
reached.write_to_be_bytes(&mut self.tm_buf[expected_len..])?;
self.verification_reporter
.completion_failure(
active_req.token,
FailParams::new(
time_stamp,
&self.user_hook.can_not_reach_mode_result_code(),
&self.tm_buf[0..expected_len + reached_len],
),
)
.map_err(|e| e.0)?;
true
}
_ => true,
};
if remove_entry {
self.active_request_map
.remove(mode_reply_with_id.request_id);
}
Ok(())
}
}
*/
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -175,7 +43,7 @@ mod tests {
ModeAndSubmode, ModeReply, ModeReplySender, ModeRequest, ModeRequestSender, ModeAndSubmode, ModeReply, ModeReplySender, ModeRequest, ModeRequestSender,
ModeRequestorAndHandlerMpsc, ModeRequestorMpsc, ModeRequestorAndHandlerMpsc, ModeRequestorMpsc,
}, },
request::GenericMessage, request::{GenericMessage, MessageMetadata},
}; };
const TEST_COMPONENT_ID_0: u64 = 5; const TEST_COMPONENT_ID_0: u64 = 5;
@ -196,24 +64,23 @@ mod tests {
.send_mode_request(request_id, TEST_COMPONENT_ID_1, sent_request) .send_mode_request(request_id, TEST_COMPONENT_ID_1, sent_request)
.expect("send failed"); .expect("send failed");
let request = request_receiver.recv().expect("recv failed"); let request = request_receiver.recv().expect("recv failed");
assert_eq!(request.request_id, 2); assert_eq!(request.request_id(), 2);
assert_eq!(request.sender_id, TEST_COMPONENT_ID_0); assert_eq!(request.sender_id(), TEST_COMPONENT_ID_0);
assert_eq!(request.message, sent_request); assert_eq!(request.message, sent_request);
// Send a reply and verify it arrives at the requestor. // Send a reply and verify it arrives at the requestor.
let mode_reply = ModeReply::ModeReply(ModeAndSubmode::new(1, 5)); let mode_reply = ModeReply::ModeReply(ModeAndSubmode::new(1, 5));
reply_sender reply_sender
.send(GenericMessage::new( .send(GenericMessage::new(
request_id, MessageMetadata::new(request_id, TEST_COMPONENT_ID_1),
TEST_COMPONENT_ID_1,
mode_reply, mode_reply,
)) ))
.expect("send failed"); .expect("send failed");
let reply = mode_requestor.try_recv_mode_reply().expect("recv failed"); let reply = mode_requestor.try_recv_mode_reply().expect("recv failed");
assert!(reply.is_some()); assert!(reply.is_some());
let reply = reply.unwrap(); let reply = reply.unwrap();
assert_eq!(reply.sender_id, TEST_COMPONENT_ID_1); assert_eq!(reply.sender_id(), TEST_COMPONENT_ID_1);
assert_eq!(reply.request_id, 2); assert_eq!(reply.request_id(), 2);
assert_eq!(reply.message, mode_reply); assert_eq!(reply.message, mode_reply);
} }
@ -252,8 +119,8 @@ mod tests {
.expect("send failed"); .expect("send failed");
let request = request_receiver_channel_1.recv().expect("recv failed"); let request = request_receiver_channel_1.recv().expect("recv failed");
assert_eq!(request.request_id, 2); assert_eq!(request.request_id(), 2);
assert_eq!(request.sender_id, TEST_COMPONENT_ID_0); assert_eq!(request.sender_id(), TEST_COMPONENT_ID_0);
assert_eq!(request.message, ModeRequest::ReadMode); assert_eq!(request.message, ModeRequest::ReadMode);
} }
@ -272,13 +139,16 @@ mod tests {
// Send a request and verify it arrives at the receiver. // Send a request and verify it arrives at the receiver.
let request_id = 2; let request_id = 2;
let sent_reply = ModeReply::ModeInfo(ModeAndSubmode::new(3, 5)); let sent_reply = ModeReply::ModeReply(ModeAndSubmode::new(3, 5));
mode_connector mode_connector
.send_mode_reply(request_id, TEST_COMPONENT_ID_2, sent_reply) .send_mode_reply(
MessageMetadata::new(request_id, TEST_COMPONENT_ID_0),
sent_reply,
)
.expect("send failed"); .expect("send failed");
let reply = reply_receiver_channel_2.recv().expect("recv failed"); let reply = reply_receiver_channel_2.recv().expect("recv failed");
assert_eq!(reply.request_id, 2); assert_eq!(reply.request_id(), 2);
assert_eq!(reply.sender_id, TEST_COMPONENT_ID_0); assert_eq!(reply.sender_id(), TEST_COMPONENT_ID_0);
assert_eq!(reply.message, sent_reply); assert_eq!(reply.message, sent_reply);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,16 @@
use super::scheduler::PusSchedulerProvider; use super::scheduler::PusSchedulerProvider;
use super::verification::{ use super::verification::{VerificationReporter, VerificationReportingProvider};
VerificationReporterWithSharedPoolMpscBoundedSender,
VerificationReporterWithSharedPoolMpscSender, VerificationReporterWithVecMpscBoundedSender,
VerificationReporterWithVecMpscSender, VerificationReportingProvider,
};
use super::{ use super::{
EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiverCore, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiverCore,
EcssTmSenderCore, MpscTcReceiver, PusServiceHelper, TmAsVecSenderWithBoundedMpsc, EcssTmSenderCore, MpscTcReceiver, MpscTmInSharedPoolSender, MpscTmInSharedPoolSenderBounded,
TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithMpsc, PusServiceHelper, PusTmAsVec,
}; };
use crate::pool::PoolProvider; use crate::pool::PoolProvider;
use crate::pus::{PusPacketHandlerResult, PusPacketHandlingError}; use crate::pus::{PusPacketHandlerResult, PusPacketHandlingError};
use alloc::string::ToString; use alloc::string::ToString;
use spacepackets::ecss::{scheduling, PusPacket}; use spacepackets::ecss::{scheduling, PusPacket};
use spacepackets::time::cds::TimeProvider; use spacepackets::time::cds::CdsTime;
use std::sync::mpsc;
/// This is a helper class for [std] environments to handle generic PUS 11 (scheduling service) /// This is a helper class for [std] environments to handle generic PUS 11 (scheduling service)
/// packets. This handler is able to handle the most important PUS requests for a scheduling /// packets. This handler is able to handle the most important PUS requests for a scheduling
@ -23,7 +20,7 @@ use spacepackets::time::cds::TimeProvider;
/// telecommands inside the scheduler. The user can retrieve the wrapped scheduler via the /// telecommands inside the scheduler. The user can retrieve the wrapped scheduler via the
/// [Self::scheduler] and [Self::scheduler_mut] function and then use the scheduler API to release /// [Self::scheduler] and [Self::scheduler_mut] function and then use the scheduler API to release
/// telecommands when applicable. /// telecommands when applicable.
pub struct PusService11SchedHandler< pub struct PusSchedServiceHandler<
TcReceiver: EcssTcReceiverCore, TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore, TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConverter,
@ -42,13 +39,7 @@ impl<
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
Scheduler: PusSchedulerProvider, Scheduler: PusSchedulerProvider,
> >
PusService11SchedHandler< PusSchedServiceHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter, Scheduler>
TcReceiver,
TmSender,
TcInMemConverter,
VerificationReporter,
Scheduler,
>
{ {
pub fn new( pub fn new(
service_helper: PusServiceHelper< service_helper: PusServiceHelper<
@ -101,14 +92,24 @@ impl<
let start_token = self let start_token = self
.service_helper .service_helper
.verif_reporter() .verif_reporter()
.start_success(ecss_tc_and_token.token, time_stamp) .start_success(
self.service_helper.common.id,
&self.service_helper.common.tm_sender,
ecss_tc_and_token.token,
time_stamp,
)
.expect("Error sending start success"); .expect("Error sending start success");
self.scheduler.enable(); self.scheduler.enable();
if self.scheduler.is_enabled() { if self.scheduler.is_enabled() {
self.service_helper self.service_helper
.verif_reporter() .verif_reporter()
.completion_success(start_token, time_stamp) .completion_success(
self.service_helper.common.id,
&self.service_helper.common.tm_sender,
start_token,
time_stamp,
)
.expect("Error sending completion success"); .expect("Error sending completion success");
} else { } else {
return Err(PusPacketHandlingError::Other( return Err(PusPacketHandlingError::Other(
@ -120,14 +121,24 @@ impl<
let start_token = self let start_token = self
.service_helper .service_helper
.verif_reporter() .verif_reporter()
.start_success(ecss_tc_and_token.token, time_stamp) .start_success(
self.service_helper.common.id,
&self.service_helper.common.tm_sender,
ecss_tc_and_token.token,
time_stamp,
)
.expect("Error sending start success"); .expect("Error sending start success");
self.scheduler.disable(); self.scheduler.disable();
if !self.scheduler.is_enabled() { if !self.scheduler.is_enabled() {
self.service_helper self.service_helper
.verif_reporter() .verif_reporter()
.completion_success(start_token, time_stamp) .completion_success(
self.service_helper.common.id,
&self.service_helper.common.tm_sender,
start_token,
time_stamp,
)
.expect("Error sending completion success"); .expect("Error sending completion success");
} else { } else {
return Err(PusPacketHandlingError::Other( return Err(PusPacketHandlingError::Other(
@ -139,7 +150,12 @@ impl<
let start_token = self let start_token = self
.service_helper .service_helper
.verif_reporter() .verif_reporter()
.start_success(ecss_tc_and_token.token, time_stamp) .start_success(
self.service_helper.common.id,
&self.service_helper.common.tm_sender,
ecss_tc_and_token.token,
time_stamp,
)
.expect("Error sending start success"); .expect("Error sending start success");
self.scheduler self.scheduler
@ -148,7 +164,12 @@ impl<
self.service_helper self.service_helper
.verif_reporter() .verif_reporter()
.completion_success(start_token, time_stamp) .completion_success(
self.service_helper.common.id,
&self.service_helper.common.tm_sender,
start_token,
time_stamp,
)
.expect("Error sending completion success"); .expect("Error sending completion success");
} }
scheduling::Subservice::TcInsertActivity => { scheduling::Subservice::TcInsertActivity => {
@ -156,17 +177,27 @@ impl<
.service_helper .service_helper
.common .common
.verif_reporter .verif_reporter
.start_success(ecss_tc_and_token.token, time_stamp) .start_success(
self.service_helper.common.id,
&self.service_helper.common.tm_sender,
ecss_tc_and_token.token,
time_stamp,
)
.expect("error sending start success"); .expect("error sending start success");
// let mut pool = self.sched_tc_pool.write().expect("locking pool failed"); // let mut pool = self.sched_tc_pool.write().expect("locking pool failed");
self.scheduler self.scheduler
.insert_wrapped_tc::<TimeProvider>(&tc, sched_tc_pool) .insert_wrapped_tc::<CdsTime>(&tc, sched_tc_pool)
.expect("insertion of activity into pool failed"); .expect("insertion of activity into pool failed");
self.service_helper self.service_helper
.verif_reporter() .verif_reporter()
.completion_success(start_token, time_stamp) .completion_success(
self.service_helper.common.id,
&self.service_helper.common.tm_sender,
start_token,
time_stamp,
)
.expect("sending completion success failed"); .expect("sending completion success failed");
} }
_ => { _ => {
@ -187,38 +218,38 @@ impl<
} }
/// Helper type definition for a PUS 11 handler with a dynamic TMTC memory backend and regular /// Helper type definition for a PUS 11 handler with a dynamic TMTC memory backend and regular
/// mpsc queues. /// mpsc queues.
pub type PusService11SchedHandlerDynWithMpsc<PusScheduler> = PusService11SchedHandler< pub type PusService11SchedHandlerDynWithMpsc<PusScheduler> = PusSchedServiceHandler<
MpscTcReceiver, MpscTcReceiver,
TmAsVecSenderWithMpsc, mpsc::Sender<PusTmAsVec>,
EcssTcInVecConverter, EcssTcInVecConverter,
VerificationReporterWithVecMpscSender, VerificationReporter,
PusScheduler, PusScheduler,
>; >;
/// Helper type definition for a PUS 11 handler with a dynamic TMTC memory backend and bounded MPSC /// Helper type definition for a PUS 11 handler with a dynamic TMTC memory backend and bounded MPSC
/// queues. /// queues.
pub type PusService11SchedHandlerDynWithBoundedMpsc<PusScheduler> = PusService11SchedHandler< pub type PusService11SchedHandlerDynWithBoundedMpsc<PusScheduler> = PusSchedServiceHandler<
MpscTcReceiver, MpscTcReceiver,
TmAsVecSenderWithBoundedMpsc, mpsc::SyncSender<PusTmAsVec>,
EcssTcInVecConverter, EcssTcInVecConverter,
VerificationReporterWithVecMpscBoundedSender, VerificationReporter,
PusScheduler, PusScheduler,
>; >;
/// Helper type definition for a PUS 11 handler with a shared store TMTC memory backend and regular /// Helper type definition for a PUS 11 handler with a shared store TMTC memory backend and regular
/// mpsc queues. /// mpsc queues.
pub type PusService11SchedHandlerStaticWithMpsc<PusScheduler> = PusService11SchedHandler< pub type PusService11SchedHandlerStaticWithMpsc<PusScheduler> = PusSchedServiceHandler<
MpscTcReceiver, MpscTcReceiver,
TmInSharedPoolSenderWithMpsc, MpscTmInSharedPoolSender,
EcssTcInSharedStoreConverter, EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscSender, VerificationReporter,
PusScheduler, PusScheduler,
>; >;
/// Helper type definition for a PUS 11 handler with a shared store TMTC memory backend and bounded /// Helper type definition for a PUS 11 handler with a shared store TMTC memory backend and bounded
/// mpsc queues. /// mpsc queues.
pub type PusService11SchedHandlerStaticWithBoundedMpsc<PusScheduler> = PusService11SchedHandler< pub type PusService11SchedHandlerStaticWithBoundedMpsc<PusScheduler> = PusSchedServiceHandler<
MpscTcReceiver, MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc, MpscTmInSharedPoolSenderBounded,
EcssTcInSharedStoreConverter, EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporter,
PusScheduler, PusScheduler,
>; >;
@ -226,7 +257,8 @@ pub type PusService11SchedHandlerStaticWithBoundedMpsc<PusScheduler> = PusServic
mod tests { mod tests {
use crate::pool::{StaticMemoryPool, StaticPoolConfig}; use crate::pool::{StaticMemoryPool, StaticPoolConfig};
use crate::pus::test_util::{PusTestHarness, TEST_APID}; use crate::pus::test_util::{PusTestHarness, TEST_APID};
use crate::pus::verification::VerificationReporterWithSharedPoolMpscBoundedSender; use crate::pus::verification::{VerificationReporter, VerificationReportingProvider};
use crate::pus::{ use crate::pus::{
scheduler::{self, PusSchedulerProvider, TcInfo}, scheduler::{self, PusSchedulerProvider, TcInfo},
tests::PusServiceHandlerWithSharedStoreCommon, tests::PusServiceHandlerWithSharedStoreCommon,
@ -234,8 +266,8 @@ mod tests {
EcssTcInSharedStoreConverter, EcssTcInSharedStoreConverter,
}; };
use crate::pus::{ use crate::pus::{
MpscTcReceiver, PusPacketHandlerResult, PusPacketHandlingError, MpscTcReceiver, MpscTmInSharedPoolSenderBounded, PusPacketHandlerResult,
TmInSharedPoolSenderWithBoundedMpsc, PusPacketHandlingError,
}; };
use alloc::collections::VecDeque; use alloc::collections::VecDeque;
use delegate::delegate; use delegate::delegate;
@ -249,15 +281,15 @@ mod tests {
time::cds, time::cds,
}; };
use super::PusService11SchedHandler; use super::PusSchedServiceHandler;
struct Pus11HandlerWithStoreTester { struct Pus11HandlerWithStoreTester {
common: PusServiceHandlerWithSharedStoreCommon, common: PusServiceHandlerWithSharedStoreCommon,
handler: PusService11SchedHandler< handler: PusSchedServiceHandler<
MpscTcReceiver, MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc, MpscTmInSharedPoolSenderBounded,
EcssTcInSharedStoreConverter, EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporter,
TestScheduler, TestScheduler,
>, >,
sched_tc_pool: StaticMemoryPool, sched_tc_pool: StaticMemoryPool,
@ -268,25 +300,39 @@ mod tests {
let test_scheduler = TestScheduler::default(); let test_scheduler = TestScheduler::default();
let pool_cfg = StaticPoolConfig::new(alloc::vec![(16, 16), (8, 32), (4, 64)], false); let pool_cfg = StaticPoolConfig::new(alloc::vec![(16, 16), (8, 32), (4, 64)], false);
let sched_tc_pool = StaticMemoryPool::new(pool_cfg.clone()); let sched_tc_pool = StaticMemoryPool::new(pool_cfg.clone());
let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new(); let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new(0);
Self { Self {
common, common,
handler: PusService11SchedHandler::new(srv_handler, test_scheduler), handler: PusSchedServiceHandler::new(srv_handler, test_scheduler),
sched_tc_pool, sched_tc_pool,
} }
} }
pub fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> { pub fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
let time_stamp = cds::TimeProvider::new_with_u16_days(0, 0).to_vec().unwrap(); let time_stamp = cds::CdsTime::new_with_u16_days(0, 0).to_vec().unwrap();
self.handler self.handler
.poll_and_handle_next_tc(&time_stamp, &mut self.sched_tc_pool) .poll_and_handle_next_tc(&time_stamp, &mut self.sched_tc_pool)
} }
} }
impl PusTestHarness for Pus11HandlerWithStoreTester { impl PusTestHarness for Pus11HandlerWithStoreTester {
fn init_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let init_token = self.handler.service_helper.verif_reporter_mut().add_tc(tc);
self.handler
.service_helper
.verif_reporter()
.acceptance_success(
self.handler.service_helper.id(),
self.handler.service_helper.tm_sender(),
init_token,
&[0; 7],
)
.expect("acceptance success failure")
}
delegate! { delegate! {
to self.common { to self.common {
fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>; fn send_tc(&self, token: &VerificationToken<TcStateAccepted>, tc: &PusTcCreator);
fn read_next_tm(&mut self) -> PusTmReader<'_>; fn read_next_tm(&mut self) -> PusTmReader<'_>;
fn check_no_tm_available(&self) -> bool; fn check_no_tm_available(&self) -> bool;
fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId); fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId);
@ -304,7 +350,7 @@ mod tests {
} }
impl PusSchedulerProvider for TestScheduler { impl PusSchedulerProvider for TestScheduler {
type TimeProvider = cds::TimeProvider; type TimeProvider = cds::CdsTime;
fn reset( fn reset(
&mut self, &mut self,
@ -330,7 +376,7 @@ mod tests {
fn insert_unwrapped_and_stored_tc( fn insert_unwrapped_and_stored_tc(
&mut self, &mut self,
_time_stamp: spacepackets::time::UnixTimestamp, _time_stamp: spacepackets::time::UnixTime,
info: crate::pus::scheduler::TcInfo, info: crate::pus::scheduler::TcInfo,
) -> Result<(), crate::pus::scheduler::ScheduleError> { ) -> Result<(), crate::pus::scheduler::ScheduleError> {
self.inserted_tcs.push_back(info); self.inserted_tcs.push_back(info);
@ -345,10 +391,11 @@ mod tests {
let mut reply_header = SpHeader::tm_unseg(TEST_APID, 0, 0).unwrap(); let mut reply_header = SpHeader::tm_unseg(TEST_APID, 0, 0).unwrap();
let tc_header = PusTcSecondaryHeader::new_simple(11, subservice as u8); let tc_header = PusTcSecondaryHeader::new_simple(11, subservice as u8);
let enable_scheduling = PusTcCreator::new(&mut reply_header, tc_header, &[0; 7], true); let enable_scheduling = PusTcCreator::new(&mut reply_header, tc_header, &[0; 7], true);
let token = test_harness.send_tc(&enable_scheduling); let token = test_harness.init_verification(&enable_scheduling);
test_harness.send_tc(&token, &enable_scheduling);
let request_id = token.request_id(); let request_id = token.request_id();
let time_stamp = cds::TimeProvider::new_with_u16_days(0, 0).to_vec().unwrap(); let time_stamp = cds::CdsTime::new_with_u16_days(0, 0).to_vec().unwrap();
test_harness test_harness
.handler .handler
.poll_and_handle_next_tc(&time_stamp, &mut test_harness.sched_tc_pool) .poll_and_handle_next_tc(&time_stamp, &mut test_harness.sched_tc_pool)
@ -392,7 +439,7 @@ mod tests {
let mut sec_header = PusTcSecondaryHeader::new_simple(17, 1); let mut sec_header = PusTcSecondaryHeader::new_simple(17, 1);
let ping_tc = PusTcCreator::new(&mut reply_header, sec_header, &[], true); let ping_tc = PusTcCreator::new(&mut reply_header, sec_header, &[], true);
let req_id_ping_tc = scheduler::RequestId::from_tc(&ping_tc); let req_id_ping_tc = scheduler::RequestId::from_tc(&ping_tc);
let stamper = cds::TimeProvider::from_now_with_u16_days().expect("time provider failed"); let stamper = cds::CdsTime::now_with_u16_days().expect("time provider failed");
let mut sched_app_data: [u8; 64] = [0; 64]; let mut sched_app_data: [u8; 64] = [0; 64];
let mut written_len = stamper.write_to_bytes(&mut sched_app_data).unwrap(); let mut written_len = stamper.write_to_bytes(&mut sched_app_data).unwrap();
let ping_raw = ping_tc.to_vec().expect("generating raw tc failed"); let ping_raw = ping_tc.to_vec().expect("generating raw tc failed");
@ -406,7 +453,8 @@ mod tests {
&sched_app_data[..written_len], &sched_app_data[..written_len],
true, true,
); );
let token = test_harness.send_tc(&enable_scheduling); let token = test_harness.init_verification(&enable_scheduling);
test_harness.send_tc(&token, &enable_scheduling);
let request_id = token.request_id(); let request_id = token.request_id();
test_harness.handle_one_tc().unwrap(); test_harness.handle_one_tc().unwrap();

View File

@ -1,20 +1,17 @@
use crate::pus::{ use crate::pus::{
PartialPusHandlingError, PusPacketHandlerResult, PusPacketHandlingError, PusTmWrapper, PartialPusHandlingError, PusPacketHandlerResult, PusPacketHandlingError, PusTmAsVec,
PusTmInPool, PusTmVariant,
}; };
use spacepackets::ecss::tm::{PusTmCreator, PusTmSecondaryHeader}; use spacepackets::ecss::tm::{PusTmCreator, PusTmSecondaryHeader};
use spacepackets::ecss::PusPacket; use spacepackets::ecss::PusPacket;
use spacepackets::SpHeader; use spacepackets::SpHeader;
use std::sync::mpsc;
use super::verification::{ use super::verification::{VerificationReporter, VerificationReportingProvider};
VerificationReporterWithSharedPoolMpscBoundedSender,
VerificationReporterWithSharedPoolMpscSender, VerificationReporterWithVecMpscBoundedSender,
VerificationReporterWithVecMpscSender, VerificationReportingProvider,
};
use super::{ use super::{
EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiverCore, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiverCore,
EcssTmSenderCore, GenericConversionError, MpscTcReceiver, PusServiceHelper, EcssTmSenderCore, GenericConversionError, MpscTcReceiver, MpscTmInSharedPoolSender,
TmAsVecSenderWithBoundedMpsc, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, MpscTmInSharedPoolSenderBounded, PusServiceHelper,
TmInSharedPoolSenderWithMpsc,
}; };
/// This is a helper class for [std] environments to handle generic PUS 17 (test service) packets. /// This is a helper class for [std] environments to handle generic PUS 17 (test service) packets.
@ -68,7 +65,12 @@ impl<
let result = self let result = self
.service_helper .service_helper
.verif_reporter() .verif_reporter()
.start_success(ecss_tc_and_token.token, time_stamp) .start_success(
self.service_helper.common.id,
&self.service_helper.common.tm_sender,
ecss_tc_and_token.token,
time_stamp,
)
.map_err(|_| PartialPusHandlingError::Verification); .map_err(|_| PartialPusHandlingError::Verification);
let start_token = if let Ok(result) = result { let start_token = if let Ok(result) = result {
Some(result) Some(result)
@ -78,14 +80,14 @@ impl<
}; };
// Sequence count will be handled centrally in TM funnel. // Sequence count will be handled centrally in TM funnel.
let mut reply_header = let mut reply_header =
SpHeader::tm_unseg(self.service_helper.common.tm_apid, 0, 0).unwrap(); SpHeader::tm_unseg(self.service_helper.verif_reporter().apid(), 0, 0).unwrap();
let tc_header = PusTmSecondaryHeader::new_simple(17, 2, time_stamp); let tc_header = PusTmSecondaryHeader::new_simple(17, 2, time_stamp);
let ping_reply = PusTmCreator::new(&mut reply_header, tc_header, &[], true); let ping_reply = PusTmCreator::new(&mut reply_header, tc_header, &[], true);
let result = self let result = self
.service_helper .service_helper
.common .common
.tm_sender .tm_sender
.send_tm(PusTmWrapper::Direct(ping_reply)) .send_tm(self.service_helper.id(), PusTmVariant::Direct(ping_reply))
.map_err(PartialPusHandlingError::TmSend); .map_err(PartialPusHandlingError::TmSend);
if let Err(err) = result { if let Err(err) = result {
partial_error = Some(err); partial_error = Some(err);
@ -95,7 +97,12 @@ impl<
if self if self
.service_helper .service_helper
.verif_reporter() .verif_reporter()
.completion_success(start_token, time_stamp) .completion_success(
self.service_helper.common.id,
&self.service_helper.common.tm_sender,
start_token,
time_stamp,
)
.is_err() .is_err()
{ {
partial_error = Some(PartialPusHandlingError::Verification) partial_error = Some(PartialPusHandlingError::Verification)
@ -120,33 +127,33 @@ impl<
/// mpsc queues. /// mpsc queues.
pub type PusService17TestHandlerDynWithMpsc = PusService17TestHandler< pub type PusService17TestHandlerDynWithMpsc = PusService17TestHandler<
MpscTcReceiver, MpscTcReceiver,
TmAsVecSenderWithMpsc, mpsc::Sender<PusTmAsVec>,
EcssTcInVecConverter, EcssTcInVecConverter,
VerificationReporterWithVecMpscSender, VerificationReporter,
>; >;
/// Helper type definition for a PUS 17 handler with a dynamic TMTC memory backend and bounded MPSC /// Helper type definition for a PUS 17 handler with a dynamic TMTC memory backend and bounded MPSC
/// queues. /// queues.
pub type PusService17TestHandlerDynWithBoundedMpsc = PusService17TestHandler< pub type PusService17TestHandlerDynWithBoundedMpsc = PusService17TestHandler<
MpscTcReceiver, MpscTcReceiver,
TmAsVecSenderWithBoundedMpsc, mpsc::SyncSender<PusTmInPool>,
EcssTcInVecConverter, EcssTcInVecConverter,
VerificationReporterWithVecMpscBoundedSender, VerificationReporter,
>; >;
/// Helper type definition for a PUS 17 handler with a shared store TMTC memory backend and regular /// Helper type definition for a PUS 17 handler with a shared store TMTC memory backend and regular
/// mpsc queues. /// mpsc queues.
pub type PusService17TestHandlerStaticWithMpsc = PusService17TestHandler< pub type PusService17TestHandlerStaticWithMpsc = PusService17TestHandler<
MpscTcReceiver, MpscTcReceiver,
TmInSharedPoolSenderWithMpsc, MpscTmInSharedPoolSender,
EcssTcInSharedStoreConverter, EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscSender, VerificationReporter,
>; >;
/// Helper type definition for a PUS 17 handler with a shared store TMTC memory backend and bounded /// Helper type definition for a PUS 17 handler with a shared store TMTC memory backend and bounded
/// mpsc queues. /// mpsc queues.
pub type PusService17TestHandlerStaticWithBoundedMpsc = PusService17TestHandler< pub type PusService17TestHandlerStaticWithBoundedMpsc = PusService17TestHandler<
MpscTcReceiver, MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc, MpscTmInSharedPoolSenderBounded,
EcssTcInSharedStoreConverter, EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporter,
>; >;
#[cfg(test)] #[cfg(test)]
@ -155,16 +162,17 @@ mod tests {
use crate::pus::tests::{ use crate::pus::tests::{
PusServiceHandlerWithSharedStoreCommon, PusServiceHandlerWithVecCommon, PusServiceHandlerWithSharedStoreCommon, PusServiceHandlerWithVecCommon,
}; };
use crate::pus::verification::std_mod::{ use crate::pus::verification::test_util::TestVerificationReporter;
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender, use crate::pus::verification::{
RequestId, VerificationReporter, VerificationReportingProvider,
}; };
use crate::pus::verification::RequestId;
use crate::pus::verification::{TcStateAccepted, VerificationToken}; use crate::pus::verification::{TcStateAccepted, VerificationToken};
use crate::pus::{ use crate::pus::{
EcssTcInSharedStoreConverter, EcssTcInVecConverter, GenericConversionError, MpscTcReceiver, EcssTcInSharedStoreConverter, EcssTcInVecConverter, GenericConversionError, MpscTcReceiver,
PusPacketHandlerResult, PusPacketHandlingError, TmAsVecSenderWithMpsc, MpscTmAsVecSender, MpscTmInSharedPoolSenderBounded, PusPacketHandlerResult,
TmInSharedPoolSenderWithBoundedMpsc, PusPacketHandlingError,
}; };
use crate::ComponentId;
use delegate::delegate; use delegate::delegate;
use spacepackets::ecss::tc::{PusTcCreator, PusTcSecondaryHeader}; use spacepackets::ecss::tc::{PusTcCreator, PusTcSecondaryHeader};
use spacepackets::ecss::tm::PusTmReader; use spacepackets::ecss::tm::PusTmReader;
@ -178,15 +186,15 @@ mod tests {
common: PusServiceHandlerWithSharedStoreCommon, common: PusServiceHandlerWithSharedStoreCommon,
handler: PusService17TestHandler< handler: PusService17TestHandler<
MpscTcReceiver, MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc, MpscTmInSharedPoolSenderBounded,
EcssTcInSharedStoreConverter, EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporter,
>, >,
} }
impl Pus17HandlerWithStoreTester { impl Pus17HandlerWithStoreTester {
pub fn new() -> Self { pub fn new(id: ComponentId) -> Self {
let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new(); let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new(id);
let pus_17_handler = PusService17TestHandler::new(srv_handler); let pus_17_handler = PusService17TestHandler::new(srv_handler);
Self { Self {
common, common,
@ -196,10 +204,24 @@ mod tests {
} }
impl PusTestHarness for Pus17HandlerWithStoreTester { impl PusTestHarness for Pus17HandlerWithStoreTester {
fn init_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let init_token = self.handler.service_helper.verif_reporter_mut().add_tc(tc);
self.handler
.service_helper
.verif_reporter()
.acceptance_success(
self.handler.service_helper.id(),
self.handler.service_helper.tm_sender(),
init_token,
&[0; 7],
)
.expect("acceptance success failure")
}
delegate! { delegate! {
to self.common { to self.common {
fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>;
fn read_next_tm(&mut self) -> PusTmReader<'_>; fn read_next_tm(&mut self) -> PusTmReader<'_>;
fn send_tc(&self, token: &VerificationToken<TcStateAccepted>, tc: &PusTcCreator);
fn check_no_tm_available(&self) -> bool; fn check_no_tm_available(&self) -> bool;
fn check_next_verification_tm( fn check_next_verification_tm(
&self, &self,
@ -211,25 +233,25 @@ mod tests {
} }
impl SimplePusPacketHandler for Pus17HandlerWithStoreTester { impl SimplePusPacketHandler for Pus17HandlerWithStoreTester {
fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> { fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
let time_stamp = cds::TimeProvider::new_with_u16_days(0, 0).to_vec().unwrap(); let time_stamp = cds::CdsTime::new_with_u16_days(0, 0).to_vec().unwrap();
self.handler.poll_and_handle_next_tc(&time_stamp) self.handler.poll_and_handle_next_tc(&time_stamp)
} }
} }
struct Pus17HandlerWithVecTester { struct Pus17HandlerWithVecTester {
common: PusServiceHandlerWithVecCommon<VerificationReporterWithVecMpscSender>, common: PusServiceHandlerWithVecCommon,
handler: PusService17TestHandler< handler: PusService17TestHandler<
MpscTcReceiver, MpscTcReceiver,
TmAsVecSenderWithMpsc, MpscTmAsVecSender,
EcssTcInVecConverter, EcssTcInVecConverter,
VerificationReporterWithVecMpscSender, TestVerificationReporter,
>, >,
} }
impl Pus17HandlerWithVecTester { impl Pus17HandlerWithVecTester {
pub fn new() -> Self { pub fn new(id: ComponentId) -> Self {
let (common, srv_handler) = let (common, srv_handler) =
PusServiceHandlerWithVecCommon::new_with_standard_verif_reporter(); PusServiceHandlerWithVecCommon::new_with_standard_verif_reporter(id);
Self { Self {
common, common,
handler: PusService17TestHandler::new(srv_handler), handler: PusService17TestHandler::new(srv_handler),
@ -238,9 +260,23 @@ mod tests {
} }
impl PusTestHarness for Pus17HandlerWithVecTester { impl PusTestHarness for Pus17HandlerWithVecTester {
fn init_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let init_token = self.handler.service_helper.verif_reporter_mut().add_tc(tc);
self.handler
.service_helper
.verif_reporter()
.acceptance_success(
self.handler.service_helper.id(),
self.handler.service_helper.tm_sender(),
init_token,
&[0; 7],
)
.expect("acceptance success failure")
}
delegate! { delegate! {
to self.common { to self.common {
fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>; fn send_tc(&self, token: &VerificationToken<TcStateAccepted>, tc: &PusTcCreator);
fn read_next_tm(&mut self) -> PusTmReader<'_>; fn read_next_tm(&mut self) -> PusTmReader<'_>;
fn check_no_tm_available(&self) -> bool; fn check_no_tm_available(&self) -> bool;
fn check_next_verification_tm( fn check_next_verification_tm(
@ -253,7 +289,7 @@ mod tests {
} }
impl SimplePusPacketHandler for Pus17HandlerWithVecTester { impl SimplePusPacketHandler for Pus17HandlerWithVecTester {
fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> { fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
let time_stamp = cds::TimeProvider::new_with_u16_days(0, 0).to_vec().unwrap(); let time_stamp = cds::CdsTime::new_with_u16_days(0, 0).to_vec().unwrap();
self.handler.poll_and_handle_next_tc(&time_stamp) self.handler.poll_and_handle_next_tc(&time_stamp)
} }
} }
@ -263,7 +299,8 @@ mod tests {
let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap(); let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap();
let sec_header = PusTcSecondaryHeader::new_simple(17, 1); let sec_header = PusTcSecondaryHeader::new_simple(17, 1);
let ping_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true); let ping_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true);
let token = test_harness.send_tc(&ping_tc); let token = test_harness.init_verification(&ping_tc);
test_harness.send_tc(&token, &ping_tc);
let request_id = token.request_id(); let request_id = token.request_id();
let result = test_harness.handle_one_tc(); let result = test_harness.handle_one_tc();
assert!(result.is_ok()); assert!(result.is_ok());
@ -288,19 +325,19 @@ mod tests {
#[test] #[test]
fn test_basic_ping_processing_using_store() { fn test_basic_ping_processing_using_store() {
let mut test_harness = Pus17HandlerWithStoreTester::new(); let mut test_harness = Pus17HandlerWithStoreTester::new(0);
ping_test(&mut test_harness); ping_test(&mut test_harness);
} }
#[test] #[test]
fn test_basic_ping_processing_using_vec() { fn test_basic_ping_processing_using_vec() {
let mut test_harness = Pus17HandlerWithVecTester::new(); let mut test_harness = Pus17HandlerWithVecTester::new(0);
ping_test(&mut test_harness); ping_test(&mut test_harness);
} }
#[test] #[test]
fn test_empty_tc_queue() { fn test_empty_tc_queue() {
let mut test_harness = Pus17HandlerWithStoreTester::new(); let mut test_harness = Pus17HandlerWithStoreTester::new(0);
let result = test_harness.handle_one_tc(); let result = test_harness.handle_one_tc();
assert!(result.is_ok()); assert!(result.is_ok());
let result = result.unwrap(); let result = result.unwrap();
@ -312,11 +349,12 @@ mod tests {
#[test] #[test]
fn test_sending_unsupported_service() { fn test_sending_unsupported_service() {
let mut test_harness = Pus17HandlerWithStoreTester::new(); let mut test_harness = Pus17HandlerWithStoreTester::new(0);
let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap(); let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap();
let sec_header = PusTcSecondaryHeader::new_simple(3, 1); let sec_header = PusTcSecondaryHeader::new_simple(3, 1);
let ping_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true); let ping_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true);
test_harness.send_tc(&ping_tc); let token = test_harness.init_verification(&ping_tc);
test_harness.send_tc(&token, &ping_tc);
let result = test_harness.handle_one_tc(); let result = test_harness.handle_one_tc();
assert!(result.is_err()); assert!(result.is_err());
let error = result.unwrap_err(); let error = result.unwrap_err();
@ -332,11 +370,12 @@ mod tests {
#[test] #[test]
fn test_sending_custom_subservice() { fn test_sending_custom_subservice() {
let mut test_harness = Pus17HandlerWithStoreTester::new(); let mut test_harness = Pus17HandlerWithStoreTester::new(0);
let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap(); let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap();
let sec_header = PusTcSecondaryHeader::new_simple(17, 200); let sec_header = PusTcSecondaryHeader::new_simple(17, 200);
let ping_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true); let ping_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true);
test_harness.send_tc(&ping_tc); let token = test_harness.init_verification(&ping_tc);
test_harness.send_tc(&token, &ping_tc);
let result = test_harness.handle_one_tc(); let result = test_harness.handle_one_tc();
assert!(result.is_ok()); assert!(result.is_ok());
let result = result.unwrap(); let result = result.unwrap();

File diff suppressed because it is too large Load Diff

View File

@ -25,21 +25,24 @@ pub type RequestId = u32;
pub type Apid = u16; pub type Apid = u16;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct TargetAndApidId { pub struct UniqueApidTargetId {
pub apid: Apid, pub apid: Apid,
pub target: u32, pub unique_id: u32,
} }
impl TargetAndApidId { impl UniqueApidTargetId {
pub const fn new(apid: Apid, target: u32) -> Self { pub const fn new(apid: Apid, target: u32) -> Self {
Self { apid, target } Self {
apid,
unique_id: target,
}
} }
pub fn raw(&self) -> ComponentId { pub fn raw(&self) -> ComponentId {
((self.apid as u64) << 32) | (self.target as u64) ((self.apid as u64) << 32) | (self.unique_id as u64)
} }
pub fn full_target_id(&self) -> ComponentId { pub fn id(&self) -> ComponentId {
self.raw() self.raw()
} }
@ -61,49 +64,78 @@ impl TargetAndApidId {
} }
} }
impl From<u64> for TargetAndApidId { impl From<u64> for UniqueApidTargetId {
fn from(raw: u64) -> Self { fn from(raw: u64) -> Self {
Self { Self {
apid: (raw >> 32) as u16, apid: (raw >> 32) as u16,
target: raw as u32, unique_id: raw as u32,
} }
} }
} }
impl From<TargetAndApidId> for u64 { impl From<UniqueApidTargetId> for u64 {
fn from(target_and_apid_id: TargetAndApidId) -> Self { fn from(target_and_apid_id: UniqueApidTargetId) -> Self {
target_and_apid_id.raw() target_and_apid_id.raw()
} }
} }
impl fmt::Display for TargetAndApidId { impl fmt::Display for UniqueApidTargetId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!( write!(
f, f,
"Target and APID ID with APID {:#03x} and target {}", "Target and APID ID with APID {:#03x} and target {}",
self.apid, self.target self.apid, self.unique_id
) )
} }
} }
#[derive(Debug, Copy, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MessageMetadata {
request_id: RequestId,
sender_id: ComponentId,
}
impl MessageMetadata {
pub const fn new(request_id: RequestId, sender_id: ComponentId) -> Self {
Self {
request_id,
sender_id,
}
}
pub fn request_id(&self) -> RequestId {
self.request_id
}
pub fn sender_id(&self) -> ComponentId {
self.sender_id
}
}
/// Generic message type which is associated with a sender using a [ChannelId] and associated /// Generic message type which is associated with a sender using a [ChannelId] and associated
/// with a request using a [RequestId]. /// with a request using a [RequestId].
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct GenericMessage<MSG> { pub struct GenericMessage<MSG> {
pub request_id: RequestId, pub requestor_info: MessageMetadata,
pub sender_id: ComponentId,
pub message: MSG, pub message: MSG,
} }
impl<MSG> GenericMessage<MSG> { impl<MSG> GenericMessage<MSG> {
pub fn new(request_id: RequestId, sender_id: ComponentId, message: MSG) -> Self { pub fn new(requestor_info: MessageMetadata, message: MSG) -> Self {
Self { Self {
request_id, requestor_info,
sender_id,
message, message,
} }
} }
delegate::delegate! {
to self.requestor_info {
pub fn request_id(&self) -> RequestId;
pub fn sender_id(&self) -> ComponentId;
}
}
} }
/// Generic trait for objects which can send targeted messages. /// Generic trait for objects which can send targeted messages.
@ -186,8 +218,7 @@ pub mod alloc_mod {
pub fn send_message( pub fn send_message(
&self, &self,
request_id: RequestId, requestor_info: MessageMetadata,
local_channel_id: ComponentId,
target_channel_id: ComponentId, target_channel_id: ComponentId,
message: MSG, message: MSG,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
@ -196,45 +227,12 @@ pub mod alloc_mod {
.0 .0
.get(&target_channel_id) .get(&target_channel_id)
.unwrap() .unwrap()
.send(GenericMessage::new(request_id, local_channel_id, message)); .send(GenericMessage::new(requestor_info, message));
} }
Err(GenericSendError::TargetDoesNotExist(target_channel_id).into()) Err(GenericSendError::TargetDoesNotExist(target_channel_id).into())
} }
} }
pub struct MessageSenderMapWithId<MSG, S: MessageSender<MSG>> {
pub local_channel_id: ComponentId,
pub message_sender_map: MessageSenderMap<MSG, S>,
}
impl<MSG, S: MessageSender<MSG>> MessageSenderMapWithId<MSG, S> {
pub fn new(local_channel_id: ComponentId) -> Self {
Self {
local_channel_id,
message_sender_map: Default::default(),
}
}
pub fn send_message(
&self,
request_id: RequestId,
target_channel_id: ComponentId,
message: MSG,
) -> Result<(), GenericTargetedMessagingError> {
self.message_sender_map.send_message(
request_id,
self.local_channel_id,
target_channel_id,
message,
)
}
pub fn add_message_target(&mut self, target_id: ComponentId, message_sender: S) {
self.message_sender_map
.add_message_target(target_id, message_sender)
}
}
pub struct MessageSenderAndReceiver<TO, FROM, S: MessageSender<TO>, R: MessageReceiver<FROM>> { pub struct MessageSenderAndReceiver<TO, FROM, S: MessageSender<TO>, R: MessageReceiver<FROM>> {
pub local_channel_id: ComponentId, pub local_channel_id: ComponentId,
pub message_sender_map: MessageSenderMap<TO, S>, pub message_sender_map: MessageSenderMap<TO, S>,
@ -265,13 +263,12 @@ pub mod alloc_mod {
pub fn send_message( pub fn send_message(
&self, &self,
request_id: RequestId, request_id: RequestId,
target_channel_id: ComponentId, target_id: ComponentId,
message: TO, message: TO,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
self.message_sender_map.send_message( self.message_sender_map.send_message(
request_id, MessageMetadata::new(request_id, self.local_channel_id_generic()),
self.local_channel_id_generic(), target_id,
target_channel_id,
message, message,
) )
} }
@ -390,9 +387,12 @@ mod tests {
ByteConversionError, SpHeader, ByteConversionError, SpHeader,
}; };
use crate::queue::{GenericReceiveError, GenericSendError, GenericTargetedMessagingError}; use crate::{
queue::{GenericReceiveError, GenericSendError, GenericTargetedMessagingError},
request::{MessageMetadata, MessageSenderMap},
};
use super::{GenericMessage, MessageReceiverWithId, MessageSenderMapWithId, TargetAndApidId}; use super::{GenericMessage, MessageReceiverWithId, UniqueApidTargetId};
const TEST_CHANNEL_ID_0: u64 = 1; const TEST_CHANNEL_ID_0: u64 = 1;
const TEST_CHANNEL_ID_1: u64 = 2; const TEST_CHANNEL_ID_1: u64 = 2;
@ -400,15 +400,15 @@ mod tests {
#[test] #[test]
fn test_basic_target_id_with_apid() { fn test_basic_target_id_with_apid() {
let id = TargetAndApidId::new(0x111, 0x01); let id = UniqueApidTargetId::new(0x111, 0x01);
assert_eq!(id.apid, 0x111); assert_eq!(id.apid, 0x111);
assert_eq!(id.target, 0x01); assert_eq!(id.unique_id, 0x01);
assert_eq!(id.full_target_id(), id.raw()); assert_eq!(id.id(), id.raw());
assert_eq!(u64::from(id), id.raw()); assert_eq!(u64::from(id), id.raw());
let id_raw = id.raw(); let id_raw = id.raw();
let id_from_raw = TargetAndApidId::from(id_raw); let id_from_raw = UniqueApidTargetId::from(id_raw);
assert_eq!(id_from_raw, id); assert_eq!(id_from_raw, id);
assert_eq!(id.full_target_id(), (0x111 << 32) | 0x01); assert_eq!(id.id(), (0x111 << 32) | 0x01);
let string = id.to_string(); let string = id.to_string();
assert_eq!( assert_eq!(
string, string,
@ -421,9 +421,9 @@ mod tests {
let mut sp_header = SpHeader::tc_unseg(0x111, 5, 0).unwrap(); let mut sp_header = SpHeader::tc_unseg(0x111, 5, 0).unwrap();
let app_data = 1_u32.to_be_bytes(); let app_data = 1_u32.to_be_bytes();
let pus_tc = PusTcCreator::new_simple(&mut sp_header, 17, 1, Some(&app_data), true); let pus_tc = PusTcCreator::new_simple(&mut sp_header, 17, 1, Some(&app_data), true);
let id = TargetAndApidId::from_pus_tc(&pus_tc).unwrap(); let id = UniqueApidTargetId::from_pus_tc(&pus_tc).unwrap();
assert_eq!(id.apid, 0x111); assert_eq!(id.apid, 0x111);
assert_eq!(id.target, 1); assert_eq!(id.unique_id, 1);
} }
#[test] #[test]
@ -431,7 +431,7 @@ mod tests {
let mut sp_header = SpHeader::tc_unseg(0x111, 5, 0).unwrap(); let mut sp_header = SpHeader::tc_unseg(0x111, 5, 0).unwrap();
let sec_header = PusTcSecondaryHeader::new_simple(17, 1); let sec_header = PusTcSecondaryHeader::new_simple(17, 1);
let pus_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true); let pus_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true);
let error = TargetAndApidId::from_pus_tc(&pus_tc); let error = UniqueApidTargetId::from_pus_tc(&pus_tc);
assert!(error.is_err()); assert!(error.is_err());
let error = error.unwrap_err(); let error = error.unwrap_err();
if let ByteConversionError::FromSliceTooSmall { found, expected } = error { if let ByteConversionError::FromSliceTooSmall { found, expected } = error {
@ -449,14 +449,17 @@ mod tests {
let receiver = MessageReceiverWithId::new(TEST_CHANNEL_ID_0, receiver); let receiver = MessageReceiverWithId::new(TEST_CHANNEL_ID_0, receiver);
let request_id = 5; let request_id = 5;
sender sender
.send(GenericMessage::new(request_id, TEST_CHANNEL_ID_1, 5)) .send(GenericMessage::new(
MessageMetadata::new(request_id, TEST_CHANNEL_ID_1),
5,
))
.unwrap(); .unwrap();
let reply = receiver.try_recv_message().unwrap(); let reply = receiver.try_recv_message().unwrap();
assert!(reply.is_some()); assert!(reply.is_some());
assert_eq!(receiver.local_channel_id(), TEST_CHANNEL_ID_0); assert_eq!(receiver.local_channel_id(), TEST_CHANNEL_ID_0);
let reply = reply.unwrap(); let reply = reply.unwrap();
assert_eq!(reply.request_id, request_id); assert_eq!(reply.requestor_info.request_id, request_id);
assert_eq!(reply.sender_id, TEST_CHANNEL_ID_1); assert_eq!(reply.requestor_info.sender_id, TEST_CHANNEL_ID_1);
assert_eq!(reply.message, 5); assert_eq!(reply.message, 5);
} }
@ -490,31 +493,43 @@ mod tests {
fn test_sender_map() { fn test_sender_map() {
let (sender0, receiver0) = mpsc::channel(); let (sender0, receiver0) = mpsc::channel();
let (sender1, receiver1) = mpsc::channel(); let (sender1, receiver1) = mpsc::channel();
let mut sender_map_with_id = MessageSenderMapWithId::new(TEST_CHANNEL_ID_0); let mut sender_map_with_id = MessageSenderMap::default();
sender_map_with_id.add_message_target(TEST_CHANNEL_ID_1, sender0); sender_map_with_id.add_message_target(TEST_CHANNEL_ID_1, sender0);
sender_map_with_id.add_message_target(TEST_CHANNEL_ID_2, sender1); sender_map_with_id.add_message_target(TEST_CHANNEL_ID_2, sender1);
sender_map_with_id sender_map_with_id
.send_message(1, TEST_CHANNEL_ID_1, 5) .send_message(
MessageMetadata::new(1, TEST_CHANNEL_ID_0),
TEST_CHANNEL_ID_1,
5,
)
.expect("sending message failed"); .expect("sending message failed");
let mut reply = receiver0.recv().expect("receiving message failed"); let mut reply = receiver0.recv().expect("receiving message failed");
assert_eq!(reply.request_id, 1); assert_eq!(reply.request_id(), 1);
assert_eq!(reply.sender_id, TEST_CHANNEL_ID_0); assert_eq!(reply.sender_id(), TEST_CHANNEL_ID_0);
assert_eq!(reply.message, 5); assert_eq!(reply.message, 5);
sender_map_with_id sender_map_with_id
.send_message(2, TEST_CHANNEL_ID_2, 10) .send_message(
MessageMetadata::new(2, TEST_CHANNEL_ID_1),
TEST_CHANNEL_ID_2,
10,
)
.expect("sending message failed"); .expect("sending message failed");
reply = receiver1.recv().expect("receiving message failed"); reply = receiver1.recv().expect("receiving message failed");
assert_eq!(reply.request_id, 2); assert_eq!(reply.request_id(), 2);
assert_eq!(reply.sender_id, TEST_CHANNEL_ID_0); assert_eq!(reply.sender_id(), TEST_CHANNEL_ID_0);
assert_eq!(reply.message, 10); assert_eq!(reply.message, 10);
} }
#[test] #[test]
fn test_sender_map_target_does_not_exist() { fn test_sender_map_target_does_not_exist() {
let (sender0, _) = mpsc::channel(); let (sender0, _) = mpsc::channel();
let mut sender_map_with_id = MessageSenderMapWithId::new(TEST_CHANNEL_ID_0); let mut sender_map_with_id = MessageSenderMap::default();
sender_map_with_id.add_message_target(TEST_CHANNEL_ID_1, sender0); sender_map_with_id.add_message_target(TEST_CHANNEL_ID_1, sender0);
let result = sender_map_with_id.send_message(1, TEST_CHANNEL_ID_2, 5); let result = sender_map_with_id.send_message(
MessageMetadata::new(1, TEST_CHANNEL_ID_0),
TEST_CHANNEL_ID_2,
5,
);
assert!(result.is_err()); assert!(result.is_err());
let error = result.unwrap_err(); let error = result.unwrap_err();
if let GenericTargetedMessagingError::Send(GenericSendError::TargetDoesNotExist(target)) = if let GenericTargetedMessagingError::Send(GenericSendError::TargetDoesNotExist(target)) =
@ -528,12 +543,20 @@ mod tests {
#[test] #[test]
fn test_sender_map_queue_full() { fn test_sender_map_queue_full() {
let (sender0, _receiver0) = mpsc::sync_channel(1); let (sender0, _receiver0) = mpsc::sync_channel(1);
let mut sender_map_with_id = MessageSenderMapWithId::new(TEST_CHANNEL_ID_0); let mut sender_map_with_id = MessageSenderMap::default();
sender_map_with_id.add_message_target(TEST_CHANNEL_ID_1, sender0); sender_map_with_id.add_message_target(TEST_CHANNEL_ID_1, sender0);
sender_map_with_id sender_map_with_id
.send_message(1, TEST_CHANNEL_ID_1, 5) .send_message(
MessageMetadata::new(1, TEST_CHANNEL_ID_0),
TEST_CHANNEL_ID_1,
5,
)
.expect("sending message failed"); .expect("sending message failed");
let result = sender_map_with_id.send_message(1, TEST_CHANNEL_ID_1, 5); let result = sender_map_with_id.send_message(
MessageMetadata::new(1, TEST_CHANNEL_ID_0),
TEST_CHANNEL_ID_1,
5,
);
assert!(result.is_err()); assert!(result.is_err());
let error = result.unwrap_err(); let error = result.unwrap_err();
if let GenericTargetedMessagingError::Send(GenericSendError::QueueFull(capacity)) = error { if let GenericTargetedMessagingError::Send(GenericSendError::QueueFull(capacity)) = error {
@ -546,10 +569,14 @@ mod tests {
#[test] #[test]
fn test_sender_map_queue_receiver_disconnected() { fn test_sender_map_queue_receiver_disconnected() {
let (sender0, receiver0) = mpsc::sync_channel(1); let (sender0, receiver0) = mpsc::sync_channel(1);
let mut sender_map_with_id = MessageSenderMapWithId::new(TEST_CHANNEL_ID_0); let mut sender_map_with_id = MessageSenderMap::default();
sender_map_with_id.add_message_target(TEST_CHANNEL_ID_1, sender0); sender_map_with_id.add_message_target(TEST_CHANNEL_ID_1, sender0);
drop(receiver0); drop(receiver0);
let result = sender_map_with_id.send_message(1, TEST_CHANNEL_ID_1, 5); let result = sender_map_with_id.send_message(
MessageMetadata::new(1, TEST_CHANNEL_ID_0),
TEST_CHANNEL_ID_1,
5,
);
assert!(result.is_err()); assert!(result.is_err());
let error = result.unwrap_err(); let error = result.unwrap_err();
if let GenericTargetedMessagingError::Send(GenericSendError::RxDisconnected) = error { if let GenericTargetedMessagingError::Send(GenericSendError::RxDisconnected) = error {

View File

@ -22,7 +22,7 @@
//! use satrs::tmtc::{ReceivesTc, ReceivesTcCore}; //! use satrs::tmtc::{ReceivesTc, ReceivesTcCore};
//! use spacepackets::{CcsdsPacket, SpHeader}; //! use spacepackets::{CcsdsPacket, SpHeader};
//! use spacepackets::ecss::WritablePusPacket; //! use spacepackets::ecss::WritablePusPacket;
//! use spacepackets::ecss::tc::{PusTc, PusTcCreator}; //! use spacepackets::ecss::tc::PusTcCreator;
//! //!
//! #[derive (Default)] //! #[derive (Default)]
//! struct ConcreteApidHandler { //! struct ConcreteApidHandler {
@ -96,6 +96,7 @@ use std::error::Error;
pub trait CcsdsPacketHandler { pub trait CcsdsPacketHandler {
type Error; type Error;
// TODO: Rework this to return a boolean based on u16 input..
fn valid_apids(&self) -> &'static [u16]; fn valid_apids(&self) -> &'static [u16];
fn handle_known_apid(&mut self, sp_header: &SpHeader, tc_raw: &[u8]) fn handle_known_apid(&mut self, sp_header: &SpHeader, tc_raw: &[u8])
-> Result<(), Self::Error>; -> Result<(), Self::Error>;

View File

@ -1,5 +1,5 @@
use spacepackets::ecss::tm::{PusTmCreator, PusTmSecondaryHeader}; use spacepackets::ecss::tm::{PusTmCreator, PusTmSecondaryHeader};
use spacepackets::time::cds::TimeProvider; use spacepackets::time::cds::CdsTime;
use spacepackets::time::TimeWriter; use spacepackets::time::TimeWriter;
use spacepackets::SpHeader; use spacepackets::SpHeader;
@ -68,7 +68,7 @@ impl PusTmWithCdsShortHelper {
source_data: &'a [u8], source_data: &'a [u8],
seq_count: u16, seq_count: u16,
) -> PusTmCreator { ) -> PusTmCreator {
let time_stamp = TimeProvider::from_now_with_u16_days().unwrap(); let time_stamp = CdsTime::now_with_u16_days().unwrap();
time_stamp.write_to_bytes(&mut self.cds_short_buf).unwrap(); time_stamp.write_to_bytes(&mut self.cds_short_buf).unwrap();
self.create_pus_tm_common(service, subservice, source_data, seq_count) self.create_pus_tm_common(service, subservice, source_data, seq_count)
} }
@ -78,7 +78,7 @@ impl PusTmWithCdsShortHelper {
service: u8, service: u8,
subservice: u8, subservice: u8,
source_data: &'a [u8], source_data: &'a [u8],
stamper: &TimeProvider, stamper: &CdsTime,
seq_count: u16, seq_count: u16,
) -> PusTmCreator { ) -> PusTmCreator {
stamper.write_to_bytes(&mut self.cds_short_buf).unwrap(); stamper.write_to_bytes(&mut self.cds_short_buf).unwrap();
@ -100,14 +100,14 @@ impl PusTmWithCdsShortHelper {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use spacepackets::{ecss::PusPacket, time::cds::TimeProvider, CcsdsPacket}; use spacepackets::{ecss::PusPacket, time::cds::CdsTime, CcsdsPacket};
use super::PusTmWithCdsShortHelper; use super::PusTmWithCdsShortHelper;
#[test] #[test]
fn test_helper_with_stamper() { fn test_helper_with_stamper() {
let mut pus_tm_helper = PusTmWithCdsShortHelper::new(0x123); let mut pus_tm_helper = PusTmWithCdsShortHelper::new(0x123);
let stamper = TimeProvider::new_with_u16_days(0, 0); let stamper = CdsTime::new_with_u16_days(0, 0);
let tm = pus_tm_helper.create_pus_tm_with_stamper(17, 1, &[1, 2, 3, 4], &stamper, 25); let tm = pus_tm_helper.create_pus_tm_with_stamper(17, 1, &[1, 2, 3, 4], &stamper, 25);
assert_eq!(tm.service(), 17); assert_eq!(tm.service(), 17);
assert_eq!(tm.subservice(), 1); assert_eq!(tm.subservice(), 1);

View File

@ -2,7 +2,7 @@
use core::mem::size_of; use core::mem::size_of;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use spacepackets::ecss::{PfcReal, PfcUnsigned, Ptc}; use spacepackets::ecss::{PfcReal, PfcUnsigned, Ptc};
use spacepackets::time::cds::TimeProvider; use spacepackets::time::cds::CdsTime;
use spacepackets::time::{CcsdsTimeProvider, TimeWriter}; use spacepackets::time::{CcsdsTimeProvider, TimeWriter};
enum NumOfParamsInfo { enum NumOfParamsInfo {
@ -36,7 +36,7 @@ struct TestMgmHkWithIndividualValidity {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct TestMgmHkWithGroupValidity { struct TestMgmHkWithGroupValidity {
last_valid_stamp: TimeProvider, last_valid_stamp: CdsTime,
valid: bool, valid: bool,
temp: f32, temp: f32,
mgm_vals: [u16; 3], mgm_vals: [u16; 3],
@ -150,7 +150,7 @@ pub fn main() {
// The easiest and probably best approach, trading off big advantages for TM downlink capacity: // The easiest and probably best approach, trading off big advantages for TM downlink capacity:
// Use a JSON format // Use a JSON format
let mgm_hk_group_validity = TestMgmHkWithGroupValidity { let mgm_hk_group_validity = TestMgmHkWithGroupValidity {
last_valid_stamp: TimeProvider::from_now_with_u16_days().unwrap(), last_valid_stamp: CdsTime::now_with_u16_days().unwrap(),
valid: false, valid: false,
temp: 20.0, temp: 20.0,
mgm_vals: [0x1f1f, 0x2f2f, 0x3f3f], mgm_vals: [0x1f1f, 0x2f2f, 0x3f3f],

View File

@ -1,13 +1,12 @@
use core::cell::Cell; use core::cell::Cell;
use std::{println, sync::mpsc}; use std::{println, sync::mpsc};
use satrs::action::ActionRequest;
use satrs::mode::{ use satrs::mode::{
ModeError, ModeProvider, ModeReplyReceiver, ModeReplySender, ModeRequestHandler, ModeError, ModeProvider, ModeReplyReceiver, ModeReplySender, ModeRequestHandler,
ModeRequestHandlerMpscBounded, ModeRequestReceiver, ModeRequestorAndHandlerMpscBounded, ModeRequestHandlerMpscBounded, ModeRequestReceiver, ModeRequestorAndHandlerMpscBounded,
ModeRequestorBoundedMpsc, ModeRequestorBoundedMpsc,
}; };
use satrs::request::RequestId; use satrs::request::{MessageMetadata, RequestId};
use satrs::{ use satrs::{
mode::{ModeAndSubmode, ModeReply, ModeRequest}, mode::{ModeAndSubmode, ModeReply, ModeRequest},
queue::GenericTargetedMessagingError, queue::GenericTargetedMessagingError,
@ -46,11 +45,30 @@ struct TestDevice {
pub name: String, pub name: String,
pub mode_node: ModeRequestHandlerMpscBounded, pub mode_node: ModeRequestHandlerMpscBounded,
pub mode_and_submode: ModeAndSubmode, pub mode_and_submode: ModeAndSubmode,
pub mode_requestor_info: Option<(RequestId, ComponentId)>, pub mode_requestor_info: Option<MessageMetadata>,
// pub action_queue: mpsc::Receiver<GenericMessage<ActionRequest>>,
} }
pub struct ModeLeafDeviceHelper {} fn mode_leaf_node_req_handler(
handler: &mut impl ModeRequestHandler,
request: GenericMessage<ModeRequest>,
) {
match request.message {
ModeRequest::SetMode(mode_and_submode) => {
handler
.start_transition(request.requestor_info, mode_and_submode)
.unwrap();
}
ModeRequest::ReadMode => handler
.send_mode_reply(
request.requestor_info,
ModeReply::ModeReply(handler.mode_and_submode()),
)
.unwrap(),
ModeRequest::AnnounceMode => handler.announce_mode(request.requestor_info, false),
ModeRequest::AnnounceModeRecursive => handler.announce_mode(request.requestor_info, true),
ModeRequest::ModeInfo(_) => todo!(),
}
}
impl TestDevice { impl TestDevice {
pub fn run(&mut self) { pub fn run(&mut self) {
@ -61,24 +79,22 @@ impl TestDevice {
if let Some(request) = self.mode_node.try_recv_mode_request()? { if let Some(request) = self.mode_node.try_recv_mode_request()? {
match request.message { match request.message {
ModeRequest::SetMode(mode_and_submode) => { ModeRequest::SetMode(mode_and_submode) => {
self.start_transition(request.request_id, request.sender_id, mode_and_submode) self.start_transition(request.requestor_info, mode_and_submode)
.unwrap(); .unwrap();
self.mode_requestor_info = Some((request.request_id, request.sender_id)); self.mode_requestor_info = Some(request.requestor_info);
} }
ModeRequest::ReadMode => self ModeRequest::ReadMode => self
.mode_node .mode_node
.send_mode_reply( .send_mode_reply(
request.request_id, request.requestor_info,
request.sender_id,
ModeReply::ModeReply(self.mode_and_submode), ModeReply::ModeReply(self.mode_and_submode),
) )
.unwrap(), .unwrap(),
ModeRequest::AnnounceMode => { ModeRequest::AnnounceMode => self.announce_mode(request.requestor_info, false),
self.announce_mode(request.request_id, request.sender_id, false)
}
ModeRequest::AnnounceModeRecursive => { ModeRequest::AnnounceModeRecursive => {
self.announce_mode(request.request_id, request.sender_id, true) self.announce_mode(request.requestor_info, true)
} }
ModeRequest::ModeInfo(_) => todo!(),
} }
} }
Ok(()) Ok(())
@ -90,39 +106,49 @@ impl ModeProvider for TestDevice {
self.mode_and_submode self.mode_and_submode
} }
} }
impl ModeRequestHandler for TestDevice { impl ModeRequestHandler for TestDevice {
fn start_transition( fn start_transition(
&mut self, &mut self,
_request_id: RequestId, requestor: MessageMetadata,
_sender_id: ComponentId,
mode_and_submode: ModeAndSubmode, mode_and_submode: ModeAndSubmode,
) -> Result<(), ModeError> { ) -> Result<(), ModeError> {
self.mode_and_submode = mode_and_submode; self.mode_and_submode = mode_and_submode;
self.handle_mode_reached()?; self.handle_mode_reached(Some(requestor))?;
Ok(()) Ok(())
} }
fn announce_mode(&self, _request_id: RequestId, _sender_id: ComponentId, _recursive: bool) { fn announce_mode(&self, requestor_info: MessageMetadata, _recursive: bool) {
println!( println!(
"{}: announcing mode: {:?}", "{}: announcing mode: {:?}",
self.name, self.mode_and_submode self.name, self.mode_and_submode
); );
} }
fn handle_mode_reached(&mut self) -> Result<(), GenericTargetedMessagingError> { fn handle_mode_reached(
let (req_id, sender_id) = self.mode_requestor_info.unwrap(); &mut self,
self.mode_node.send_mode_reply(
req_id, requestor: Option<MessageMetadata>,
sender_id, ) -> Result<(), GenericTargetedMessagingError> {
ModeReply::ModeReply(self.mode_and_submode), if let Some(requestor) = requestor {
)?; self.send_mode_reply(requestor, ModeReply::ModeReply(self.mode_and_submode))?;
}
Ok(())
}
fn send_mode_reply(
&self,
requestor_info: MessageMetadata,
reply: ModeReply,
) -> Result<(), GenericTargetedMessagingError> {
self.mode_node
.send_mode_reply(requestor_info, ModeReply::ModeReply(self.mode_and_submode))?;
Ok(()) Ok(())
} }
} }
struct TestAssembly { struct TestAssembly {
pub mode_node: ModeRequestorAndHandlerMpscBounded, pub mode_node: ModeRequestorAndHandlerMpscBounded,
pub mode_requestor_info: Option<(RequestId, ComponentId)>, pub mode_requestor_info: Option<MessageMetadata>,
pub mode_and_submode: ModeAndSubmode, pub mode_and_submode: ModeAndSubmode,
pub target_mode_and_submode: Option<ModeAndSubmode>, pub target_mode_and_submode: Option<ModeAndSubmode>,
} }
@ -143,23 +169,21 @@ impl TestAssembly {
if let Some(request) = self.mode_node.try_recv_mode_request()? { if let Some(request) = self.mode_node.try_recv_mode_request()? {
match request.message { match request.message {
ModeRequest::SetMode(mode_and_submode) => { ModeRequest::SetMode(mode_and_submode) => {
self.start_transition(request.request_id, request.sender_id, mode_and_submode) self.start_transition(request.requestor_info, mode_and_submode)
.unwrap(); .unwrap();
} }
ModeRequest::ReadMode => self ModeRequest::ReadMode => self
.mode_node .mode_node
.send_mode_reply( .send_mode_reply(
request.request_id, request.requestor_info,
request.sender_id,
ModeReply::ModeReply(self.mode_and_submode), ModeReply::ModeReply(self.mode_and_submode),
) )
.unwrap(), .unwrap(),
ModeRequest::AnnounceMode => { ModeRequest::AnnounceMode => self.announce_mode(request.requestor_info, false),
self.announce_mode(request.request_id, request.sender_id, false)
}
ModeRequest::AnnounceModeRecursive => { ModeRequest::AnnounceModeRecursive => {
self.announce_mode(request.request_id, request.sender_id, true) self.announce_mode(request.requestor_info, true)
} }
ModeRequest::ModeInfo(_) => todo!(),
} }
} }
Ok(()) Ok(())
@ -168,18 +192,20 @@ impl TestAssembly {
pub fn check_mode_replies(&mut self) -> Result<(), GenericTargetedMessagingError> { pub fn check_mode_replies(&mut self) -> Result<(), GenericTargetedMessagingError> {
if let Some(reply_and_id) = self.mode_node.try_recv_mode_reply()? { if let Some(reply_and_id) = self.mode_node.try_recv_mode_reply()? {
match reply_and_id.message { match reply_and_id.message {
ModeReply::ModeInfo(_) => todo!(),
ModeReply::ModeReply(reply) => { ModeReply::ModeReply(reply) => {
println!( println!(
"TestAssembly: Received mode reply from {:?}, reached: {:?}", "TestAssembly: Received mode reply from {:?}, reached: {:?}",
reply_and_id.sender_id, reply reply_and_id.sender_id(),
reply
); );
} }
ModeReply::CantReachMode(_) => todo!(), ModeReply::CantReachMode(_) => todo!(),
ModeReply::WrongMode { expected, reached } => { ModeReply::WrongMode { expected, reached } => {
println!( println!(
"TestAssembly: Wrong mode reply from {:?}, reached {:?}, expected {:?}", "TestAssembly: Wrong mode reply from {:?}, reached {:?}, expected {:?}",
reply_and_id.sender_id, reached, expected reply_and_id.sender_id(),
reached,
expected
); );
} }
} }
@ -191,16 +217,15 @@ impl TestAssembly {
impl ModeRequestHandler for TestAssembly { impl ModeRequestHandler for TestAssembly {
fn start_transition( fn start_transition(
&mut self, &mut self,
request_id: RequestId, requestor: MessageMetadata,
sender_id: ComponentId,
mode_and_submode: ModeAndSubmode, mode_and_submode: ModeAndSubmode,
) -> Result<(), ModeError> { ) -> Result<(), ModeError> {
self.mode_requestor_info = Some((request_id, sender_id)); self.mode_requestor_info = Some(requestor);
self.target_mode_and_submode = Some(mode_and_submode); self.target_mode_and_submode = Some(mode_and_submode);
Ok(()) Ok(())
} }
fn announce_mode(&self, request_id: RequestId, _sender_id: ComponentId, recursive: bool) { fn announce_mode(&self, requestor_info: MessageMetadata, recursive: bool) {
println!( println!(
"TestAssembly: Announcing mode (recursively: {}): {:?}", "TestAssembly: Announcing mode (recursively: {}): {:?}",
recursive, self.mode_and_submode recursive, self.mode_and_submode
@ -217,21 +242,33 @@ impl ModeRequestHandler for TestAssembly {
.for_each(|(_, sender)| { .for_each(|(_, sender)| {
sender sender
.send(GenericMessage::new( .send(GenericMessage::new(
request_id, MessageMetadata::new(
self.mode_node.local_channel_id_generic(), requestor_info.request_id(),
self.mode_node.local_channel_id_generic(),
),
mode_request, mode_request,
)) ))
.expect("sending mode request failed"); .expect("sending mode request failed");
}); });
} }
fn handle_mode_reached(&mut self) -> Result<(), GenericTargetedMessagingError> { fn handle_mode_reached(
let (req_id, sender_id) = self.mode_requestor_info.unwrap(); &mut self,
self.mode_node.send_mode_reply( mode_requestor: Option<MessageMetadata>,
req_id, ) -> Result<(), GenericTargetedMessagingError> {
sender_id, if let Some(requestor) = mode_requestor {
ModeReply::ModeReply(self.mode_and_submode), self.send_mode_reply(requestor, ModeReply::ModeReply(self.mode_and_submode))?;
)?; }
Ok(())
}
fn send_mode_reply(
&self,
requestor: MessageMetadata,
reply: ModeReply,
) -> Result<(), GenericTargetedMessagingError> {
self.mode_node
.send_mode_reply(requestor, ModeReply::ModeReply(self.mode_and_submode))?;
Ok(()) Ok(())
} }
} }

View File

@ -5,7 +5,8 @@ use satrs::events::{EventU32, EventU32TypedSev, Severity, SeverityInfo};
use satrs::params::U32Pair; use satrs::params::U32Pair;
use satrs::params::{Params, ParamsHeapless, WritableToBeBytes}; use satrs::params::{Params, ParamsHeapless, WritableToBeBytes};
use satrs::pus::event_man::{DefaultPusEventMgmtBackend, EventReporter, PusEventDispatcher}; use satrs::pus::event_man::{DefaultPusEventMgmtBackend, EventReporter, PusEventDispatcher};
use satrs::pus::TmAsVecSenderWithMpsc; use satrs::pus::PusTmAsVec;
use satrs::request::UniqueApidTargetId;
use spacepackets::ecss::tm::PusTmReader; use spacepackets::ecss::tm::PusTmReader;
use spacepackets::ecss::{PusError, PusPacket}; use spacepackets::ecss::{PusError, PusPacket};
use std::sync::mpsc::{self, SendError, TryRecvError}; use std::sync::mpsc::{self, SendError, TryRecvError};
@ -15,6 +16,8 @@ const INFO_EVENT: EventU32TypedSev<SeverityInfo> =
EventU32TypedSev::<SeverityInfo>::const_new(1, 0); EventU32TypedSev::<SeverityInfo>::const_new(1, 0);
const LOW_SEV_EVENT: EventU32 = EventU32::const_new(Severity::LOW, 1, 5); const LOW_SEV_EVENT: EventU32 = EventU32::const_new(Severity::LOW, 1, 5);
const EMPTY_STAMP: [u8; 7] = [0; 7]; const EMPTY_STAMP: [u8; 7] = [0; 7];
const TEST_APID: u16 = 0x02;
const TEST_ID: UniqueApidTargetId = UniqueApidTargetId::new(TEST_APID, 0x05);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum CustomTmSenderError { pub enum CustomTmSenderError {
@ -32,13 +35,12 @@ fn test_threaded_usage() {
let pus_event_man_send_provider = EventU32SenderMpsc::new(1, pus_event_man_tx); let pus_event_man_send_provider = EventU32SenderMpsc::new(1, pus_event_man_tx);
event_man.subscribe_all(pus_event_man_send_provider.target_id()); event_man.subscribe_all(pus_event_man_send_provider.target_id());
event_man.add_sender(pus_event_man_send_provider); event_man.add_sender(pus_event_man_send_provider);
let (event_tx, event_rx) = mpsc::channel(); let (event_tx, event_rx) = mpsc::channel::<PusTmAsVec>();
let reporter = EventReporter::new(0x02, 128).expect("Creating event reporter failed"); let reporter =
let mut pus_event_man = EventReporter::new(TEST_ID.raw(), 0x02, 128).expect("Creating event reporter failed");
PusEventDispatcher::new(reporter, DefaultPusEventMgmtBackend::default()); let pus_event_man = PusEventDispatcher::new(reporter, DefaultPusEventMgmtBackend::default());
// PUS + Generic event manager thread // PUS + Generic event manager thread
let jh0 = thread::spawn(move || { let jh0 = thread::spawn(move || {
let mut sender = TmAsVecSenderWithMpsc::new(0, "event_sender", event_tx);
let mut event_cnt = 0; let mut event_cnt = 0;
let mut params_array: [u8; 128] = [0; 128]; let mut params_array: [u8; 128] = [0; 128];
loop { loop {
@ -46,9 +48,9 @@ fn test_threaded_usage() {
assert!(res.is_ok()); assert!(res.is_ok());
match pus_event_man_rx.try_recv() { match pus_event_man_rx.try_recv() {
Ok((event, aux_data)) => { Ok((event, aux_data)) => {
let mut gen_event = |aux_data| { let gen_event = |aux_data| {
pus_event_man.generate_pus_event_tm_generic( pus_event_man.generate_pus_event_tm_generic(
&mut sender, &event_tx,
&EMPTY_STAMP, &EMPTY_STAMP,
event, event,
aux_data, aux_data,
@ -101,8 +103,8 @@ fn test_threaded_usage() {
match event_rx.try_recv() { match event_rx.try_recv() {
// Event TM received successfully // Event TM received successfully
Ok(event_tm) => { Ok(event_tm) => {
let tm = let tm = PusTmReader::new(event_tm.packet.as_slice(), 7)
PusTmReader::new(event_tm.as_slice(), 7).expect("Deserializing TM failed"); .expect("Deserializing TM failed");
assert_eq!(tm.0.service(), 5); assert_eq!(tm.0.service(), 5);
assert_eq!(tm.0.subservice(), 1); assert_eq!(tm.0.subservice(), 1);
let src_data = tm.0.source_data(); let src_data = tm.0.source_data();
@ -127,8 +129,8 @@ fn test_threaded_usage() {
match event_rx.try_recv() { match event_rx.try_recv() {
// Event TM received successfully // Event TM received successfully
Ok(event_tm) => { Ok(event_tm) => {
let tm = let tm = PusTmReader::new(event_tm.packet.as_slice(), 7)
PusTmReader::new(event_tm.as_slice(), 7).expect("Deserializing TM failed"); .expect("Deserializing TM failed");
assert_eq!(tm.0.service(), 5); assert_eq!(tm.0.service(), 5);
assert_eq!(tm.0.subservice(), 2); assert_eq!(tm.0.subservice(), 2);
let src_data = tm.0.source_data(); let src_data = tm.0.source_data();

View File

@ -3,10 +3,11 @@ pub mod crossbeam_test {
use hashbrown::HashMap; use hashbrown::HashMap;
use satrs::pool::{PoolProvider, PoolProviderWithGuards, StaticMemoryPool, StaticPoolConfig}; use satrs::pool::{PoolProvider, PoolProviderWithGuards, StaticMemoryPool, StaticPoolConfig};
use satrs::pus::verification::{ use satrs::pus::verification::{
FailParams, RequestId, VerificationReporterCfg, VerificationReporterWithSender, FailParams, RequestId, VerificationReporter, VerificationReporterCfg,
VerificationReportingProvider, VerificationReportingProvider,
}; };
use satrs::pus::TmInSharedPoolSenderWithCrossbeam; use satrs::pus::TmInSharedPoolSenderWithCrossbeam;
use satrs::request::UniqueApidTargetId;
use satrs::tmtc::tm_helper::SharedTmPool; use satrs::tmtc::tm_helper::SharedTmPool;
use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader}; use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader};
use spacepackets::ecss::tm::PusTmReader; use spacepackets::ecss::tm::PusTmReader;
@ -17,6 +18,8 @@ pub mod crossbeam_test {
use std::time::Duration; use std::time::Duration;
const TEST_APID: u16 = 0x03; const TEST_APID: u16 = 0x03;
const TEST_ID: TargetAndApidId = TargetAndApidId::new(TEST_APID, 0x05);
const FIXED_STAMP: [u8; 7] = [0; 7]; const FIXED_STAMP: [u8; 7] = [0; 7];
const PACKETS_SENT: u8 = 8; const PACKETS_SENT: u8 = 8;
@ -40,13 +43,9 @@ pub mod crossbeam_test {
let shared_tc_pool_0 = Arc::new(RwLock::new(StaticMemoryPool::new(pool_cfg))); let shared_tc_pool_0 = Arc::new(RwLock::new(StaticMemoryPool::new(pool_cfg)));
let shared_tc_pool_1 = shared_tc_pool_0.clone(); let shared_tc_pool_1 = shared_tc_pool_0.clone();
let (tx, rx) = crossbeam_channel::bounded(10); let (tx, rx) = crossbeam_channel::bounded(10);
let sender = TmInSharedPoolSenderWithCrossbeam::new( let sender_0 = TmInSharedPoolSenderWithCrossbeam::new(shared_tm_pool.clone(), tx.clone());
0, let sender_1 = sender_0.clone();
"verif_sender", let mut reporter_with_sender_0 = VerificationReporter::new(&cfg);
shared_tm_pool.clone(),
tx.clone(),
);
let mut reporter_with_sender_0 = VerificationReporterWithSender::new(&cfg, sender);
let mut reporter_with_sender_1 = reporter_with_sender_0.clone(); let mut reporter_with_sender_1 = reporter_with_sender_0.clone();
// For test purposes, we retrieve the request ID from the TCs and pass them to the receiver // For test purposes, we retrieve the request ID from the TCs and pass them to the receiver
// tread. // tread.
@ -93,24 +92,36 @@ pub mod crossbeam_test {
let token = reporter_with_sender_0.add_tc_with_req_id(req_id_0); let token = reporter_with_sender_0.add_tc_with_req_id(req_id_0);
let accepted_token = reporter_with_sender_0 let accepted_token = reporter_with_sender_0
.acceptance_success(token, &FIXED_STAMP) .acceptance_success(TEST_ID.raw(), &sender_0, token, &FIXED_STAMP)
.expect("Acceptance success failed"); .expect("Acceptance success failed");
// Do some start handling here // Do some start handling here
let started_token = reporter_with_sender_0 let started_token = reporter_with_sender_0
.start_success(accepted_token, &FIXED_STAMP) .start_success(TEST_ID.raw(), &sender_0, accepted_token, &FIXED_STAMP)
.expect("Start success failed"); .expect("Start success failed");
// Do some step handling here // Do some step handling here
reporter_with_sender_0 reporter_with_sender_0
.step_success(&started_token, &FIXED_STAMP, EcssEnumU8::new(0)) .step_success(
TEST_ID.raw(),
&sender_0,
&started_token,
&FIXED_STAMP,
EcssEnumU8::new(0),
)
.expect("Start success failed"); .expect("Start success failed");
// Finish up // Finish up
reporter_with_sender_0 reporter_with_sender_0
.step_success(&started_token, &FIXED_STAMP, EcssEnumU8::new(1)) .step_success(
TEST_ID.raw(),
&sender_0,
&started_token,
&FIXED_STAMP,
EcssEnumU8::new(1),
)
.expect("Start success failed"); .expect("Start success failed");
reporter_with_sender_0 reporter_with_sender_0
.completion_success(started_token, &FIXED_STAMP) .completion_success(TEST_ID.raw(), &sender_0, started_token, &FIXED_STAMP)
.expect("Completion success failed"); .expect("Completion success failed");
}); });
@ -128,15 +139,15 @@ pub mod crossbeam_test {
let (tc, _) = PusTcReader::new(&tc_buf[0..tc_len]).unwrap(); let (tc, _) = PusTcReader::new(&tc_buf[0..tc_len]).unwrap();
let token = reporter_with_sender_1.add_tc(&tc); let token = reporter_with_sender_1.add_tc(&tc);
let accepted_token = reporter_with_sender_1 let accepted_token = reporter_with_sender_1
.acceptance_success(token, &FIXED_STAMP) .acceptance_success(TEST_ID.raw(), &sender_1, token, &FIXED_STAMP)
.expect("Acceptance success failed"); .expect("Acceptance success failed");
let started_token = reporter_with_sender_1 let started_token = reporter_with_sender_1
.start_success(accepted_token, &FIXED_STAMP) .start_success(TEST_ID.raw(), &sender_1, accepted_token, &FIXED_STAMP)
.expect("Start success failed"); .expect("Start success failed");
let fail_code = EcssEnumU16::new(2); let fail_code = EcssEnumU16::new(2);
let params = FailParams::new_no_fail_data(&FIXED_STAMP, &fail_code); let params = FailParams::new_no_fail_data(&FIXED_STAMP, &fail_code);
reporter_with_sender_1 reporter_with_sender_1
.completion_failure(started_token, params) .completion_failure(TEST_ID.raw(), &sender_1, started_token, params)
.expect("Completion success failed"); .expect("Completion success failed");
}); });
@ -145,14 +156,14 @@ pub mod crossbeam_test {
let mut tm_buf: [u8; 1024] = [0; 1024]; let mut tm_buf: [u8; 1024] = [0; 1024];
let mut verif_map = HashMap::new(); let mut verif_map = HashMap::new();
while packet_counter < PACKETS_SENT { while packet_counter < PACKETS_SENT {
let verif_addr = rx let tm_in_pool = rx
.recv_timeout(Duration::from_millis(50)) .recv_timeout(Duration::from_millis(50))
.expect("Packet reception timeout"); .expect("Packet reception timeout");
let tm_len; let tm_len;
let shared_tm_store = shared_tm_pool.clone_backing_pool(); let shared_tm_store = shared_tm_pool.clone_backing_pool();
{ {
let mut rg = shared_tm_store.write().expect("Error locking shared pool"); let mut rg = shared_tm_store.write().expect("Error locking shared pool");
let store_guard = rg.read_with_guard(verif_addr); let store_guard = rg.read_with_guard(tm_in_pool.store_addr);
tm_len = store_guard tm_len = store_guard
.read(&mut tm_buf) .read(&mut tm_buf)
.expect("Error reading TM slice"); .expect("Error reading TM slice");