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"
thiserror = "1"
derive-new = "0.5"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
[dependencies.satrs]
# version = "0.2.0-rc.0"
path = "../satrs"
features = ["test_util"]
[dependencies.satrs-mib]
# version = "0.1.1"
version = "0.1.1"
path = "../satrs-mib"
[features]

View File

@ -1,44 +1,123 @@
// TODO: Remove this at a later stage.
#![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::{Arc, Mutex};
use satrs::mode::{ModeAndSubmode, ModeProvider, ModeReply, ModeRequest, ModeRequestHandler};
use satrs::pus::EcssTmSenderCore;
use satrs::request::GenericMessage;
use satrs::pus::{EcssTmSenderCore, PusTmVariant};
use satrs::request::{GenericMessage, MessageMetadata, UniqueApidTargetId};
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 serde::{Deserialize, Serialize};
pub trait SpiInterface {
type 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 x: f32,
pub y: f32,
pub z: f32,
}
#[derive(new)]
pub struct MgmHandler<ComInterface: SpiInterface, TmSender: EcssTmSenderCore> {
id: ComponentId,
id: UniqueApidTargetId,
dev_str: &'static str,
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_parent: mpsc::Sender<GenericMessage<ModeReply>>,
composite_request_receiver: mpsc::Receiver<GenericMessage<CompositeRequest>>,
hk_reply_sender: mpsc::Sender<GenericMessage<HkReply>>,
hk_tm_sender: TmSender,
mode: ModeAndSubmode,
spi_interface: ComInterface,
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> {
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
@ -54,23 +133,37 @@ impl<ComInterface: SpiInterface, TmSender: EcssTmSenderCore> ModeRequestHandler
{
fn start_transition(
&mut self,
request_id: satrs::request::RequestId,
sender_id: ComponentId,
requestor: MessageMetadata,
mode_and_submode: ModeAndSubmode,
) -> Result<(), satrs::mode::ModeError> {
todo!()
self.mode = mode_and_submode;
self.handle_mode_reached(Some(requestor))?;
Ok(())
}
fn announce_mode(
&self,
request_id: satrs::request::RequestId,
sender_id: satrs::ComponentId,
recursive: bool,
) {
fn announce_mode(&self, _requestor_info: MessageMetadata, _recursive: bool) {
log::info!("{} announcing mode: {:?}", self.dev_str, self.mode);
}
fn handle_mode_reached(&mut self) -> Result<(), satrs::queue::GenericTargetedMessagingError> {
todo!()
fn handle_mode_reached(
&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> {
timestamp: [u8; 7],
time_provider: TimeProvider<DaysLen16Bits>,
time_provider: CdsTime<DaysLen16Bits>,
verif_reporter: VerificationReporter,
tm_sender: Box<dyn EcssTmSender>,
request_rx: mpsc::Receiver<RequestWithToken>,
@ -17,7 +17,7 @@ impl<VerificationReporter: VerificationReportingProvider> AcsTask<VerificationRe
) -> Self {
Self {
timestamp: [0; 7],
time_provider: TimeProvider::new_with_u16_days(0, 0),
time_provider: CdsTime::new_with_u16_days(0, 0),
verif_reporter,
tm_sender: Box::new(tm_sender),
request_rx,

View File

@ -1,7 +1,7 @@
use satrs::pus::ReceivesEcssPusTc;
use satrs::spacepackets::{CcsdsPacket, SpHeader};
use satrs::tmtc::{CcsdsPacketHandler, ReceivesCcsdsTc};
use satrs_example::config::PUS_APID;
use satrs_example::config::components::Apid;
#[derive(Clone)]
pub struct CcsdsReceiver<
@ -19,7 +19,12 @@ impl<
type Error = E;
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(
@ -27,7 +32,8 @@ impl<
sp_header: &SpHeader,
tc_raw: &[u8],
) -> 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);
}
Ok(())

View File

@ -9,8 +9,6 @@ use satrs::{
pool::{StaticMemoryPool, StaticPoolConfig},
};
pub const PUS_APID: u16 = 0x02;
#[derive(Copy, Clone, PartialEq, Eq, Debug, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
pub enum CustomPusServiceId {
@ -102,14 +100,51 @@ pub mod mode_err {
pub const WRONG_MODE: ResultU16 = ResultU16::new(GroupId::Mode as u8, 0);
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum ComponentIdList {
PusVerification = 0,
EventManagement = 1,
PusTest = 2,
PusAction = 3,
PusSched = 4,
PusHk = 5,
pub mod components {
use satrs::request::UniqueApidTargetId;
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Apid {
VerificationTm = 1,
Sched = 2,
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 {

View File

@ -1,5 +1,8 @@
use std::sync::mpsc::{self};
use crate::pus::create_verification_reporter;
use satrs::pus::verification::VerificationReporter;
use satrs::pus::EcssTmSenderCore;
use satrs::{
event_man::{
EventManagerWithBoundedMpsc, EventSendProvider, EventU32SenderMpscBounded,
@ -12,44 +15,51 @@ use satrs::{
DefaultPusEventU32Dispatcher, EventReporter, EventRequest, EventRequestWithToken,
},
verification::{TcStateStarted, VerificationReportingProvider, VerificationToken},
EcssTmSender,
},
spacepackets::time::cds::{self, TimeProvider},
spacepackets::time::cds::CdsTime,
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;
/// 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.
pub struct PusEventHandler<VerificationReporter: VerificationReportingProvider> {
pub struct PusEventHandler<TmSender: EcssTmSenderCore> {
id: ComponentId,
event_request_rx: mpsc::Receiver<EventRequestWithToken>,
pus_event_dispatcher: DefaultPusEventU32Dispatcher<()>,
pus_event_man_rx: mpsc::Receiver<(EventU32, Option<Params>)>,
tm_sender: Box<dyn EcssTmSender>,
time_provider: TimeProvider,
tm_sender: TmSender,
time_provider: CdsTime,
timestamp: [u8; 7],
verif_handler: VerificationReporter,
}
impl<VerificationReporter: VerificationReportingProvider> PusEventHandler<VerificationReporter> {
impl<TmSender: EcssTmSenderCore> PusEventHandler<TmSender> {
pub fn new(
id: ComponentId,
tm_sender: TmSender,
verif_handler: VerificationReporter,
event_manager: &mut EventManagerWithBoundedMpsc,
event_request_rx: mpsc::Receiver<EventRequestWithToken>,
tm_sender: impl EcssTmSender,
) -> Self {
let event_queue_cap = 30;
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
// 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 =
DefaultPusEventU32Dispatcher::new_with_default_backend(event_reporter);
let pus_event_man_send_provider = EventU32SenderMpscBounded::new(
ComponentIdList::EventManagement as ComponentId,
PUS_EVENT_MANAGEMENT.raw(),
pus_event_man_tx,
event_queue_cap,
);
@ -58,13 +68,14 @@ impl<VerificationReporter: VerificationReportingProvider> PusEventHandler<Verifi
event_manager.add_sender(pus_event_man_send_provider);
Self {
id,
event_request_rx,
pus_event_dispatcher,
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],
verif_handler,
tm_sender: Box::new(tm_sender),
tm_sender,
}
}
@ -75,7 +86,7 @@ impl<VerificationReporter: VerificationReportingProvider> PusEventHandler<Verifi
.try_into()
.expect("expected start verification token");
self.verif_handler
.completion_success(started_token, timestamp)
.completion_success(self.id, &self.tm_sender, started_token, timestamp)
.expect("Sending completion success failed");
};
// handle event requests
@ -104,12 +115,7 @@ impl<VerificationReporter: VerificationReportingProvider> PusEventHandler<Verifi
if let Ok((event, _param)) = self.pus_event_man_rx.try_recv() {
update_time(&mut self.time_provider, &mut self.timestamp);
self.pus_event_dispatcher
.generate_pus_event_tm_generic(
self.tm_sender.upcast_mut(),
&self.timestamp,
event,
None,
)
.generate_pus_event_tm_generic(&mut self.tm_sender, &self.timestamp, event, None)
.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 pus_event_handler: PusEventHandler<VerificationReporter>,
pub pus_event_handler: PusEventHandler<TmSender>,
}
impl<VerificationReporter: VerificationReportingProvider> EventHandler<VerificationReporter> {
impl<TmSender: EcssTmSenderCore> EventHandler<TmSender> {
pub fn new(
tm_sender: impl EcssTmSender,
verif_handler: VerificationReporter,
tm_sender: TmSender,
event_request_rx: mpsc::Receiver<EventRequestWithToken>,
) -> Self {
let mut event_man_wrapper = EventManagerWrapper::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_request_rx,
tm_sender,
);
Self {
event_man_wrapper,

View File

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

View File

@ -1 +1,39 @@
use satrs::spacepackets::time::{cds::CdsTime, TimeWriter};
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 satrs::hal::std::tcp_server::ServerConfig;
use satrs::hal::std::udp_server::UdpTcServer;
use satrs::request::{GenericMessage, TargetAndApidId};
use satrs::request::GenericMessage;
use satrs::tmtc::tm_helper::SharedTmPool;
use satrs_example::config::pool::{create_sched_tc_pool, create_static_pools};
use satrs_example::config::tasks::{
FREQ_MS_AOCS, FREQ_MS_EVENT_HANDLING, FREQ_MS_PUS_STACK, FREQ_MS_UDP_TMTC,
};
use satrs_example::config::{
ComponentIdList, RequestTargetId, OBSW_SERVER_ADDR, PUS_APID, SERVER_PORT,
};
use satrs_example::config::{OBSW_SERVER_ADDR, SERVER_PORT};
use tmtc::PusTcSourceProviderDynamic;
use udp::DynamicUdpTmHandler;
// use crate::acs::AcsTask;
use crate::acs::mgm::{MgmHandler, SpiDummyInterface};
use crate::ccsds::CcsdsReceiver;
use crate::logger::setup_logger;
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::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::test::create_test_service_static;
use crate::pus::{PusReceiver, PusTcMpscRouter};
@ -44,27 +43,18 @@ use crate::tmtc::{
PusTcSourceProviderSharedPool, SharedTcPool, TcSourceTaskDynamic, TcSourceTaskStatic,
};
use crate::udp::{StaticUdpTmHandler, UdpTmtcServer};
use satrs::mode::ModeRequest;
use satrs::pus::event_man::EventRequestWithToken;
use satrs::pus::verification::{VerificationReporterCfg, VerificationReporterWithSender};
use satrs::pus::{EcssTmSender, TmAsVecSenderWithId, TmInSharedPoolSenderWithId};
use satrs::spacepackets::{time::cds::TimeProvider, time::TimeWriter};
use satrs::pus::TmInSharedPoolSender;
use satrs::spacepackets::{time::cds::CdsTime, time::TimeWriter};
use satrs::tmtc::CcsdsDistributor;
use satrs::ComponentId;
use satrs_example::config::components::MGM_HANDLER_0;
use std::net::{IpAddr, SocketAddr};
use std::sync::mpsc::{self, channel};
use std::sync::mpsc;
use std::sync::{Arc, RwLock};
use std::thread;
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)]
fn static_tmtc_pool_main() {
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_server_tx, tm_server_rx) = mpsc::sync_channel(50);
// Every software component which needs to generate verification telemetry, receives a cloned
// verification reporter.
let verif_reporter = create_verification_reporter(TmInSharedPoolSenderWithId::new(
ComponentIdList::PusVerification as ComponentId,
"verif_sender",
shared_tm_pool.clone(),
tm_funnel_tx.clone(),
));
let tm_funnel_tx_sender =
TmInSharedPoolSender::new(shared_tm_pool.clone(), tm_funnel_tx.clone());
let (mgm_handler_composite_tx, mgm_handler_composite_rx) =
mpsc::channel::<GenericMessage<CompositeRequest>>();
let (mgm_handler_mode_tx, mgm_handler_mode_rx) = mpsc::channel::<GenericMessage<ModeRequest>>();
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.
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
// 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
// in the sat-rs documentation.
let mut event_handler = EventHandler::new(
TmInSharedPoolSenderWithId::new(
ComponentIdList::EventManagement as ComponentId,
"ALL_EVENTS_TX",
shared_tm_pool.clone(),
tm_funnel_tx.clone(),
),
verif_reporter.clone(),
event_request_rx,
);
let mut event_handler = EventHandler::new(tm_funnel_tx.clone(), event_request_rx);
let (pus_test_tx, pus_test_rx) = channel();
let (pus_event_tx, pus_event_rx) = channel();
let (pus_sched_tx, pus_sched_rx) = channel();
let (pus_hk_tx, pus_hk_rx) = channel();
let (pus_action_tx, pus_action_rx) = channel();
let (pus_test_tx, pus_test_rx) = mpsc::channel();
let (pus_event_tx, pus_event_rx) = mpsc::channel();
let (pus_sched_tx, pus_sched_rx) = mpsc::channel();
let (pus_hk_tx, pus_hk_rx) = mpsc::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_hk_reply_tx, pus_hk_reply_rx) = channel();
let (_pus_action_reply_tx, pus_action_reply_rx) = mpsc::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 {
test_service_receiver: pus_test_tx,
event_service_receiver: pus_event_tx,
sched_service_receiver: pus_sched_tx,
hk_service_receiver: pus_hk_tx,
action_service_receiver: pus_action_tx,
test_tc_sender: pus_test_tx,
event_tc_sender: pus_event_tx,
sched_tc_sender: pus_sched_tx,
hk_tc_sender: pus_hk_tx,
action_tc_sender: pus_action_tx,
mode_tc_sender: pus_mode_tx,
};
let pus_test_service = create_test_service_static(
shared_tm_pool.clone(),
tm_funnel_tx.clone(),
verif_reporter.clone(),
tm_funnel_tx_sender.clone(),
shared_tc_pool.pool.clone(),
event_handler.clone_event_sender(),
pus_test_rx,
);
let pus_scheduler_service = create_scheduler_service_static(
shared_tm_pool.clone(),
tm_funnel_tx.clone(),
verif_reporter.clone(),
tm_funnel_tx_sender.clone(),
tc_source.clone(),
pus_sched_rx,
create_sched_tc_pool(),
);
let pus_event_service = create_event_service_static(
shared_tm_pool.clone(),
tm_funnel_tx.clone(),
verif_reporter.clone(),
tm_funnel_tx_sender.clone(),
shared_tc_pool.pool.clone(),
pus_event_rx,
event_request_tx,
);
let pus_action_service = create_action_service_static(
shared_tm_pool.clone(),
tm_funnel_tx.clone(),
verif_reporter.clone(),
tm_funnel_tx_sender.clone(),
shared_tc_pool.pool.clone(),
pus_action_rx,
request_map.clone(),
pus_action_reply_rx,
);
let pus_hk_service = create_hk_service_static(
shared_tm_pool.clone(),
tm_funnel_tx.clone(),
verif_reporter.clone(),
tm_funnel_tx_sender.clone(),
shared_tc_pool.pool.clone(),
pus_hk_rx,
request_map,
request_map.clone(),
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(
pus_test_service,
pus_hk_service,
pus_event_service,
pus_action_service,
pus_scheduler_service,
pus_test_service,
pus_mode_service,
);
let ccsds_receiver = CcsdsReceiver { tc_source };
let mut tmtc_task = TcSourceTaskStatic::new(
shared_tc_pool.clone(),
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);
@ -211,19 +194,6 @@ fn static_tmtc_pool_main() {
)
.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(
shared_tm_pool,
sync_tm_tcp_source,
@ -231,6 +201,24 @@ fn static_tmtc_pool_main() {
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");
let jh_udp_tmtc = thread::Builder::new()
.name("TMTC and UDP".to_string())
@ -276,7 +264,7 @@ fn static_tmtc_pool_main() {
let jh_aocs = thread::Builder::new()
.name("AOCS".to_string())
.spawn(move || loop {
// acs_task.periodic_operation();
mgm_handler.periodic_operation();
thread::sleep(Duration::from_millis(FREQ_MS_AOCS));
})
.unwrap();
@ -310,22 +298,23 @@ fn static_tmtc_pool_main() {
#[allow(dead_code)]
fn dyn_tmtc_pool_main() {
let (tc_source_tx, tc_source_rx) = channel();
let (tm_funnel_tx, tm_funnel_rx) = channel();
let (tm_server_tx, tm_server_rx) = channel();
// Every software component which needs to generate verification telemetry, gets a cloned
// verification reporter.
let verif_reporter = create_verification_reporter(TmAsVecSenderWithId::new(
ComponentIdList::PusVerification as ComponentId,
"verif_sender",
tm_funnel_tx.clone(),
));
let (tc_source_tx, tc_source_rx) = mpsc::channel();
let (tm_funnel_tx, tm_funnel_rx) = mpsc::channel();
let (tm_server_tx, tm_server_rx) = mpsc::channel();
// Some request are targetable. This map is used to retrieve sender handles based on a target ID.
let (mgm_handler_composite_tx, mgm_handler_composite_rx) =
mpsc::channel::<GenericMessage<CompositeRequest>>();
let (mgm_handler_mode_tx, mgm_handler_mode_rx) = mpsc::channel::<GenericMessage<ModeRequest>>();
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.
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);
@ -335,80 +324,74 @@ fn dyn_tmtc_pool_main() {
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
// in the sat-rs documentation.
let mut event_handler = EventHandler::new(
TmAsVecSenderWithId::new(
ComponentIdList::EventManagement as ComponentId,
"ALL_EVENTS_TX",
tm_funnel_tx.clone(),
),
verif_reporter.clone(),
event_request_rx,
);
let mut event_handler = EventHandler::new(tm_funnel_tx.clone(), event_request_rx);
let (pus_test_tx, pus_test_rx) = channel();
let (pus_event_tx, pus_event_rx) = channel();
let (pus_sched_tx, pus_sched_rx) = channel();
let (pus_hk_tx, pus_hk_rx) = channel();
let (pus_action_tx, pus_action_rx) = channel();
let (pus_test_tx, pus_test_rx) = mpsc::channel();
let (pus_event_tx, pus_event_rx) = mpsc::channel();
let (pus_sched_tx, pus_sched_rx) = mpsc::channel();
let (pus_hk_tx, pus_hk_rx) = mpsc::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_hk_reply_tx, pus_hk_reply_rx) = channel();
let (_pus_action_reply_tx, pus_action_reply_rx) = mpsc::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 {
test_service_receiver: pus_test_tx,
event_service_receiver: pus_event_tx,
sched_service_receiver: pus_sched_tx,
hk_service_receiver: pus_hk_tx,
action_service_receiver: pus_action_tx,
test_tc_sender: pus_test_tx,
event_tc_sender: pus_event_tx,
sched_tc_sender: pus_sched_tx,
hk_tc_sender: pus_hk_tx,
action_tc_sender: pus_action_tx,
mode_tc_sender: pus_mode_tx,
};
let pus_test_service = create_test_service_dynamic(
tm_funnel_tx.clone(),
verif_reporter.clone(),
event_handler.clone_event_sender(),
pus_test_rx,
);
let pus_scheduler_service = create_scheduler_service_dynamic(
tm_funnel_tx.clone(),
verif_reporter.clone(),
tc_source.0.clone(),
pus_sched_rx,
create_sched_tc_pool(),
);
let pus_event_service = create_event_service_dynamic(
tm_funnel_tx.clone(),
verif_reporter.clone(),
pus_event_rx,
event_request_tx,
);
let pus_event_service =
create_event_service_dynamic(tm_funnel_tx.clone(), pus_event_rx, event_request_tx);
let pus_action_service = create_action_service_dynamic(
tm_funnel_tx.clone(),
verif_reporter.clone(),
pus_action_rx,
request_map.clone(),
pus_action_reply_rx,
);
let pus_hk_service = create_hk_service_dynamic(
tm_funnel_tx.clone(),
verif_reporter.clone(),
pus_hk_rx,
request_map,
request_map.clone(),
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(
pus_test_service,
pus_hk_service,
pus_event_service,
pus_action_service,
pus_scheduler_service,
pus_test_service,
pus_mode_service,
);
let ccsds_receiver = CcsdsReceiver { tc_source };
let mut tmtc_task = TcSourceTaskDynamic::new(
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);
@ -432,19 +415,25 @@ fn dyn_tmtc_pool_main() {
)
.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 (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");
let jh_udp_tmtc = thread::Builder::new()
.name("TMTC and UDP".to_string())
@ -490,7 +479,7 @@ fn dyn_tmtc_pool_main() {
let jh_aocs = thread::Builder::new()
.name("AOCS".to_string())
.spawn(move || loop {
// acs_task.periodic_operation();
mgm_handler.periodic_operation();
thread::sleep(Duration::from_millis(FREQ_MS_AOCS));
})
.unwrap();
@ -531,7 +520,7 @@ fn 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
.update_from_now()
.expect("Could not get current time");

View File

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

View File

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

@ -2,8 +2,8 @@ use crate::requests::GenericRequestRouter;
use crate::tmtc::MpscStoreAndSendError;
use log::warn;
use satrs::pus::verification::{
self, FailParams, TcStateAccepted, TcStateStarted, VerificationReportingProvider,
VerificationToken,
self, FailParams, TcStateAccepted, TcStateStarted, VerificationReporter,
VerificationReporterCfg, VerificationReportingProvider, VerificationToken,
};
use satrs::pus::{
ActiveRequestMapProvider, ActiveRequestProvider, EcssTcAndToken, EcssTcInMemConverter,
@ -12,13 +12,13 @@ use satrs::pus::{
PusRequestRouter, PusServiceHelper, PusTcToRequestConverter, TcInMemory,
};
use satrs::queue::GenericReceiveError;
use satrs::request::GenericMessage;
use satrs::request::{Apid, GenericMessage, MessageMetadata};
use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::PusServiceId;
use satrs::spacepackets::time::cds::TimeProvider;
use satrs::spacepackets::time::TimeWriter;
use satrs::ComponentId;
use satrs_example::config::components::PUS_ROUTING_SERVICE;
use satrs_example::config::{tmtc_err, CustomPusServiceId};
use satrs_example::TimeStampHelper;
use std::fmt::Debug;
use std::sync::mpsc::{self, Sender};
@ -30,58 +30,125 @@ pub mod scheduler;
pub mod stack;
pub mod test;
/// Simple router structure which forwards PUS telecommands to dedicated handlers.
pub struct PusTcMpscRouter {
pub test_service_receiver: Sender<EcssTcAndToken>,
pub event_service_receiver: Sender<EcssTcAndToken>,
pub sched_service_receiver: Sender<EcssTcAndToken>,
pub hk_service_receiver: Sender<EcssTcAndToken>,
pub action_service_receiver: Sender<EcssTcAndToken>,
pub fn create_verification_reporter(apid: Apid) -> VerificationReporter {
let verif_cfg = VerificationReporterCfg::new(apid, 1, 2, 8).unwrap();
// Every software component which needs to generate verification telemetry, gets a cloned
// verification reporter.
VerificationReporter::new(&verif_cfg)
}
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 pus_router: PusTcMpscRouter,
stamp_helper: TimeStampHelper,
}
struct TimeStampHelper {
stamper: TimeProvider,
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 {
impl<TmSender: EcssTmSenderCore> PusReceiver<TmSender> {
pub fn new(tm_sender: TmSender, pus_router: PusTcMpscRouter) -> Self {
Self {
stamper: TimeProvider::from_now_with_u16_days().expect("creating time stamper failed"),
time_stamp: Default::default(),
}
}
}
impl<VerificationReporter: VerificationReportingProvider> PusReceiver<VerificationReporter> {
pub fn new(verif_reporter: VerificationReporter, pus_router: PusTcMpscRouter) -> Self {
Self {
verif_reporter,
id: PUS_ROUTING_SERVICE.raw(),
tm_sender,
verif_reporter: create_verification_reporter(PUS_ROUTING_SERVICE.apid),
pus_router,
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 {
@ -123,7 +190,6 @@ pub struct PusTargetedRequestService<
RequestType,
ReplyType,
> {
pub id: ComponentId,
pub service_helper:
PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
pub request_router: GenericRequestRouter,
@ -162,7 +228,6 @@ where
GenericRequestRouter: PusRequestRouter<RequestType, Error = GenericRoutingError>,
{
pub fn new(
id: ComponentId,
service_helper: PusServiceHelper<
TcReceiver,
TmSender,
@ -176,7 +241,6 @@ where
reply_receiver: mpsc::Receiver<GenericMessage<ReplyType>>,
) -> Self {
Self {
id,
service_helper,
request_converter,
active_request_map,
@ -201,10 +265,12 @@ where
.cache(&ecss_tc_and_token.tc_in_memory)?;
let tc = self.service_helper.tc_in_mem_converter().convert()?;
let (mut request_info, request) = match self.request_converter.convert(
self.service_helper.id(),
ecss_tc_and_token.token,
&tc,
time_stamp,
self.service_helper.tm_sender(),
&self.service_helper.common.verif_reporter,
time_stamp,
) {
Ok((info, req)) => (info, req),
Err(e) => {
@ -218,8 +284,7 @@ where
.expect("token not in expected accepted state");
let verif_request_id = verification::RequestId::new(&tc).raw();
match self.request_router.route(
verif_request_id,
self.id,
MessageMetadata::new(verif_request_id, self.service_helper.id()),
request_info.target_id(),
request,
) {
@ -227,7 +292,12 @@ where
let started_token = self
.service_helper
.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");
request_info.set_token(started_token.into());
self.active_request_map
@ -238,8 +308,9 @@ where
&request_info,
&tc,
e.clone(),
time_stamp,
self.service_helper.tm_sender(),
self.service_helper.verif_reporter(),
time_stamp,
);
return Err(e.into());
}
@ -259,6 +330,8 @@ where
self.service_helper
.verif_reporter()
.completion_failure(
self.service_helper.id(),
self.service_helper.tm_sender(),
token,
FailParams::new(time_stamp, &tmtc_err::INVALID_PUS_SERVICE, &service_slice),
)
@ -269,6 +342,8 @@ where
self.service_helper
.verif_reporter()
.completion_failure(
self.service_helper.id(),
self.service_helper.tm_sender(),
token,
FailParams::new(
time_stamp,
@ -284,6 +359,8 @@ where
self.service_helper
.verif_reporter()
.completion_failure(
self.service_helper.id(),
self.service_helper.tm_sender(),
token,
FailParams::new(time_stamp, &tmtc_err::NOT_ENOUGH_APP_DATA, &context_info),
)
@ -314,25 +391,29 @@ where
reply: &GenericMessage<ReplyType>,
time_stamp: &[u8],
) -> 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() {
self.reply_handler
.handle_unrequested_reply(reply, &self.service_helper.common.tm_sender)?;
self.reply_handler.handle_unrequested_reply(
self.service_helper.id(),
reply,
&self.service_helper.common.tm_sender,
)?;
return Ok(());
}
let active_request = active_req_opt.unwrap();
let request_finished = self
.reply_handler
.handle_reply(
self.service_helper.id(),
reply,
active_request,
&self.service_helper.common.tm_sender,
&self.service_helper.common.verif_reporter,
time_stamp,
&self.service_helper.common.tm_sender,
)
.unwrap_or(false);
if request_finished {
self.active_request_map.remove(reply.request_id);
self.active_request_map.remove(reply.request_id());
}
Ok(())
}
@ -356,6 +437,8 @@ where
/// Generic timeout handling: Handle the verification failure with a dedicated return code
/// and also log the error.
pub fn generic_pus_request_timeout_handler(
sender_id: ComponentId,
sender: &(impl EcssTmSenderCore + ?Sized),
active_request: &(impl ActiveRequestProvider + Debug),
verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8],
@ -366,118 +449,27 @@ pub fn generic_pus_request_timeout_handler(
.token()
.try_into()
.expect("token not in expected started state");
verification_handler
.completion_failure(
started_token,
FailParams::new(
time_stamp,
&satrs_example::config::tmtc_err::REQUEST_TIMEOUT,
&[],
),
)
.map_err(|e| e.0)?;
verification_handler.completion_failure(
sender_id,
sender,
started_token,
FailParams::new(time_stamp, &tmtc_err::REQUEST_TIMEOUT, &[]),
)?;
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)]
pub(crate) mod tests {
use std::time::Duration;
use satrs::pus::test_util::TEST_COMPONENT_ID;
use satrs::pus::{MpscTmAsVecSender, PusTmAsVec, PusTmVariant};
use satrs::{
pus::{
verification::{
test_util::{SharedVerificationMap, TestVerificationReporter},
VerificationReporterWithVecMpscSender,
},
ActivePusRequestStd, ActiveRequestMapProvider, EcssTcInVecConverter, MpscTcReceiver,
TmAsVecSenderWithMpsc,
verification::test_util::TestVerificationReporter, ActivePusRequestStd,
ActiveRequestMapProvider, EcssTcInVecConverter, MpscTcReceiver,
},
request::TargetAndApidId,
request::UniqueApidTargetId,
spacepackets::{
ecss::{
tc::{PusTcCreator, PusTcSecondaryHeader},
@ -491,22 +483,18 @@ pub(crate) mod tests {
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
pub struct ReplyHandlerTestbench<
ReplyHandler: PusReplyHandler<ActiveRequestInfo, Reply, Error = EcssTmtcError>,
ActiveRequestInfo: ActiveRequestProvider,
Reply,
> {
pub shared_verif_map: SharedVerificationMap,
pub id: ComponentId,
pub verif_reporter: TestVerificationReporter,
pub reply_handler: ReplyHandler,
pub tm_receiver: mpsc::Receiver<Vec<u8>>,
pub tm_receiver: mpsc::Receiver<PusTmAsVec>,
pub default_timeout: Duration,
tm_sender: TmAsVecSenderWithMpsc,
tm_sender: MpscTmAsVecSender,
phantom: std::marker::PhantomData<(ActiveRequestInfo, Reply)>,
}
@ -517,15 +505,14 @@ pub(crate) mod tests {
> ReplyHandlerTestbench<ReplyHandler, ActiveRequestInfo, Reply>
{
pub fn new(reply_handler: ReplyHandler) -> Self {
let shared_verif_map = SharedVerificationMap::default();
let test_verif_reporter = TestVerificationReporter::new(shared_verif_map.clone());
let test_verif_reporter = TestVerificationReporter::default();
let (tm_sender, tm_receiver) = mpsc::channel();
Self {
shared_verif_map,
id: TEST_COMPONENT_ID.raw(),
verif_reporter: test_verif_reporter,
reply_handler,
default_timeout: Duration::from_secs(30),
tm_sender: TmAsVecSenderWithMpsc::new(0, "TEST_SENDER", tm_sender),
tm_sender,
tm_receiver,
phantom: std::marker::PhantomData,
}
@ -547,16 +534,16 @@ pub(crate) mod tests {
));
let accepted = self
.verif_reporter
.acceptance_success(init, time_stamp)
.acceptance_success(self.id, &self.tm_sender, init, time_stamp)
.expect("acceptance failed");
let started = self
.verif_reporter
.start_success(accepted, time_stamp)
.start_success(self.id, &self.tm_sender, accepted, time_stamp)
.expect("start failed");
(
started.request_id(),
ActivePusRequestStd::new(
TargetAndApidId::new(apid, apid_target).raw(),
UniqueApidTargetId::new(apid, apid_target).raw(),
started,
self.default_timeout,
),
@ -570,11 +557,12 @@ pub(crate) mod tests {
time_stamp: &[u8],
) -> Result<bool, ReplyHandler::Error> {
self.reply_handler.handle_reply(
self.id,
reply,
active_request,
&self.tm_sender,
&self.verif_reporter,
time_stamp,
&self.tm_sender,
)
}
@ -583,7 +571,32 @@ pub(crate) mod tests {
reply: &GenericMessage<Reply>,
) -> Result<(), ReplyHandler::Error> {
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,
Request,
> {
pub shared_verif_map: SharedVerificationMap,
pub id: ComponentId,
pub verif_reporter: TestVerificationReporter,
pub converter: Converter,
dummy_sender: DummySender,
current_request_id: Option<verification::RequestId>,
current_packet: Option<Vec<u8>>,
phantom: std::marker::PhantomData<(ActiveRequestInfo, Request)>,
@ -608,12 +622,12 @@ pub(crate) mod tests {
> PusConverterTestbench<Converter, ActiveRequestInfo, Request>
{
pub fn new(converter: Converter) -> Self {
let shared_verif_map = SharedVerificationMap::default();
let test_verif_reporter = TestVerificationReporter::new(shared_verif_map.clone());
let test_verif_reporter = TestVerificationReporter::default();
Self {
shared_verif_map,
id: TEST_COMPONENT_ID.raw(),
verif_reporter: test_verif_reporter,
converter,
dummy_sender: DummySender::default(),
current_request_id: None,
current_packet: None,
phantom: std::marker::PhantomData,
@ -625,7 +639,7 @@ pub(crate) mod tests {
self.current_request_id = Some(verification::RequestId::new(tc));
self.current_packet = Some(tc.to_vec().unwrap());
self.verif_reporter
.acceptance_success(token, &[])
.acceptance_success(self.id, &self.dummy_sender, token, &[])
.expect("acceptance failed")
}
@ -647,16 +661,21 @@ pub(crate) mod tests {
}
let current_packet = self.current_packet.take().unwrap();
let tc_reader = PusTcReader::new(&current_packet).unwrap();
let (active_info, request) =
self.converter
.convert(token, &tc_reader.0, time_stamp, &self.verif_reporter)?;
let (active_info, request) = self.converter.convert(
self.id,
token,
&tc_reader.0,
&self.dummy_sender,
&self.verif_reporter,
time_stamp,
)?;
assert_eq!(
active_info.token().request_id(),
self.request_id().expect("no request id is set")
);
assert_eq!(
active_info.target_id(),
TargetAndApidId::new(expected_apid, expected_apid_target).raw()
UniqueApidTargetId::new(expected_apid, expected_apid_target).raw()
);
Ok((active_info, request))
}
@ -672,9 +691,9 @@ pub(crate) mod tests {
> {
pub service: PusTargetedRequestService<
MpscTcReceiver,
TmAsVecSenderWithMpsc,
MpscTmAsVecSender,
EcssTcInVecConverter,
VerificationReporterWithVecMpscSender,
TestVerificationReporter,
RequestConverter,
ReplyHandler,
ActiveRequestMap,
@ -682,8 +701,7 @@ pub(crate) mod tests {
RequestType,
ReplyType,
>,
pub verif_reporter: VerificationReporterWithVecMpscSender,
pub tm_funnel_rx: mpsc::Receiver<Vec<u8>>,
pub tm_funnel_rx: mpsc::Receiver<PusTmAsVec>,
pub pus_packet_tx: mpsc::Sender<EcssTcAndToken>,
pub reply_tx: mpsc::Sender<GenericMessage<ReplyType>>,
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 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::{
mode::{ModeAndSubmode, ModeReply, ModeRequest},
pus::{
@ -9,9 +20,9 @@ use satrs::{
VerificationToken,
},
ActivePusRequestStd, ActiveRequestProvider, EcssTmSenderCore, EcssTmtcError,
GenericConversionError, PusReplyHandler, PusTcToRequestConverter, PusTmWrapper,
GenericConversionError, PusReplyHandler, PusTcToRequestConverter, PusTmVariant,
},
request::TargetAndApidId,
request::UniqueApidTargetId,
spacepackets::{
ecss::{
tc::PusTcReader,
@ -20,10 +31,15 @@ use satrs::{
},
SpHeader,
},
ComponentId,
};
use satrs_example::config::components::PUS_MODE_SERVICE;
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)]
pub struct ModeReplyHandler {}
@ -33,7 +49,8 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
fn handle_unrequested_reply(
&mut self,
reply: &satrs::request::GenericMessage<ModeReply>,
_caller_id: ComponentId,
reply: &GenericMessage<ModeReply>,
_tm_sender: &impl EcssTmSenderCore,
) -> Result<(), Self::Error> {
log::warn!("received unexpected reply for mode service 5: {reply:?}");
@ -42,30 +59,24 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
fn handle_reply(
&mut self,
reply: &satrs::request::GenericMessage<ModeReply>,
caller_id: ComponentId,
reply: &GenericMessage<ModeReply>,
active_request: &ActivePusRequestStd,
tm_sender: &impl EcssTmSenderCore,
verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8],
tm_sender: &impl EcssTmSenderCore,
) -> Result<bool, Self::Error> {
let started_token: VerificationToken<TcStateStarted> = active_request
.token()
.try_into()
.expect("invalid token state");
match reply.message {
ModeReply::ModeInfo(info) => {
log::warn!(
"received unrequest mode information for active request {:?}: {:?}",
active_request,
info
);
}
ModeReply::ModeReply(mode_reply) => {
let mut source_data: [u8; 12] = [0; 12];
mode_reply
.write_to_be_bytes(&mut source_data)
.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)
.expect("generating SP header failed");
let sec_header = PusTmSecondaryHeader::new(
@ -76,18 +87,21 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
Some(time_stamp),
);
let pus_tm = PusTmCreator::new(&mut sp_header, sec_header, &source_data, true);
tm_sender.send_tm(PusTmWrapper::Direct(pus_tm))?;
verification_handler
.completion_success(started_token, time_stamp)
.map_err(|e| e.0)?;
tm_sender.send_tm(caller_id, PusTmVariant::Direct(pus_tm))?;
verification_handler.completion_success(
caller_id,
tm_sender,
started_token,
time_stamp,
)?;
}
ModeReply::CantReachMode(error_code) => {
verification_handler
.completion_failure(
started_token,
FailParams::new(time_stamp, &error_code, &[]),
)
.map_err(|e| e.0)?;
verification_handler.completion_failure(
caller_id,
tm_sender,
started_token,
FailParams::new(time_stamp, &error_code, &[]),
)?;
}
ModeReply::WrongMode { expected, reached } => {
let mut error_info: [u8; 24] = [0; 24];
@ -97,16 +111,16 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
written_len += reached
.write_to_be_bytes(&mut error_info[ModeAndSubmode::RAW_LEN..])
.expect("writing reached mode failed");
verification_handler
.completion_failure(
started_token,
FailParams::new(
time_stamp,
&mode_err::WRONG_MODE,
&error_info[..written_len],
),
)
.map_err(|e| e.0)?;
verification_handler.completion_failure(
caller_id,
tm_sender,
started_token,
FailParams::new(
time_stamp,
&mode_err::WRONG_MODE,
&error_info[..written_len],
),
)?;
}
};
Ok(true)
@ -114,12 +128,15 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
fn handle_request_timeout(
&mut self,
caller_id: ComponentId,
active_request: &ActivePusRequestStd,
tm_sender: &impl EcssTmSenderCore,
verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8],
_tm_sender: &impl EcssTmSenderCore,
) -> Result<(), Self::Error> {
generic_pus_request_timeout_handler(
caller_id,
tm_sender,
active_request,
verification_handler,
time_stamp,
@ -137,16 +154,21 @@ impl PusTcToRequestConverter<ActivePusRequestStd, ModeRequest> for ModeRequestCo
fn convert(
&mut self,
caller_id: ComponentId,
token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader,
time_stamp: &[u8],
tm_sender: &(impl EcssTmSenderCore + ?Sized),
verif_reporter: &impl VerificationReportingProvider,
time_stamp: &[u8],
) -> Result<(ActivePusRequestStd, ModeRequest), Self::Error> {
let subservice = tc.subservice();
let user_data = tc.user_data();
let not_enough_app_data = |expected: usize| {
verif_reporter
.start_failure(
caller_id,
tm_sender,
token,
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>() {
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 =
ActivePusRequestStd::new(target_id_and_apid.into(), token, Duration::from_secs(30));
let subservice_typed = Subservice::try_from(subservice);
@ -167,6 +189,8 @@ impl PusTcToRequestConverter<ActivePusRequestStd, ModeRequest> for ModeRequestCo
// Invalid subservice
verif_reporter
.start_failure(
caller_id,
tm_sender,
token,
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)]
mod tests {
use satrs::pus::test_util::{TEST_APID, TEST_COMPONENT_ID, TEST_UNIQUE_ID};
use satrs::request::MessageMetadata;
use satrs::{
mode::{ModeAndSubmode, ModeReply, ModeRequest},
pus::mode::Subservice,
@ -207,10 +340,11 @@ mod tests {
SpHeader,
},
};
use satrs_example::config::tmtc_err;
use crate::pus::{
mode::ModeReplyHandler,
tests::{PusConverterTestbench, ReplyHandlerTestbench, TEST_APID, TEST_APID_TARGET_ID},
tests::{PusConverterTestbench, ReplyHandlerTestbench},
};
use super::ModeRequestConverter;
@ -221,11 +355,11 @@ mod tests {
let mut sp_header = SpHeader::tc_unseg(TEST_APID, 0, 0).unwrap();
let sec_header = PusTcSecondaryHeader::new_simple(200, Subservice::TcReadMode as u8);
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 token = testbench.add_tc(&tc);
let (_active_req, req) = testbench
.convert(token, &[], TEST_APID, TEST_APID_TARGET_ID)
.convert(token, &[], TEST_APID, TEST_UNIQUE_ID)
.expect("conversion has failed");
assert_eq!(req, ModeRequest::ReadMode);
}
@ -237,14 +371,14 @@ mod tests {
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 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
.write_to_be_bytes(&mut app_data[4..])
.unwrap();
let tc = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true);
let token = testbench.add_tc(&tc);
let (_active_req, req) = testbench
.convert(token, &[], TEST_APID, TEST_APID_TARGET_ID)
.convert(token, &[], TEST_APID, TEST_UNIQUE_ID)
.expect("conversion has failed");
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 sec_header = PusTcSecondaryHeader::new_simple(200, Subservice::TcAnnounceMode as u8);
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 token = testbench.add_tc(&tc);
let (_active_req, req) = testbench
.convert(token, &[], TEST_APID, TEST_APID_TARGET_ID)
.convert(token, &[], TEST_APID, TEST_UNIQUE_ID)
.expect("conversion has failed");
assert_eq!(req, ModeRequest::AnnounceMode);
}
@ -271,11 +405,11 @@ mod tests {
let sec_header =
PusTcSecondaryHeader::new_simple(200, Subservice::TcAnnounceModeRecursive as u8);
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 token = testbench.add_tc(&tc);
let (_active_req, req) = testbench
.convert(token, &[], TEST_APID, TEST_APID_TARGET_ID)
.convert(token, &[], TEST_APID, TEST_UNIQUE_ID)
.expect("conversion has failed");
assert_eq!(req, ModeRequest::AnnounceModeRecursive);
}
@ -283,8 +417,9 @@ mod tests {
#[test]
fn reply_handling_unrequested_reply() {
let mut testbench = ReplyHandlerTestbench::new(ModeReplyHandler::default());
let mode_reply = ModeReply::ModeInfo(ModeAndSubmode::new(5, 1));
let unrequested_reply = GenericMessage::new(10_u32, 15_u64, mode_reply);
let mode_reply = ModeReply::ModeReply(ModeAndSubmode::new(5, 1));
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
// weird stuff.
let result = testbench.handle_unrequested_reply(&unrequested_reply);
@ -294,9 +429,14 @@ mod tests {
#[test]
fn reply_handling_reply_timeout() {
let mut testbench = ReplyHandlerTestbench::new(ModeReplyHandler::default());
// TODO: Start a request, then time it out with the API and check verification completion
// failure.
// testbench.reply_handler.handle_request_timeout(active_request, verification_handler, time_stamp, tm_sender)
// testbench.default_timeout = Duration::from_millis(50);
let (req_id, active_request) = testbench.add_tc(TEST_APID, TEST_UNIQUE_ID, &[]);
let result = testbench.handle_request_timeout(&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,23 +1,18 @@
use std::sync::mpsc;
use std::time::Duration;
use crate::pus::create_verification_reporter;
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_srv::PusService11SchedHandler;
use satrs::pus::verification::std_mod::{
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender,
};
use satrs::pus::verification::VerificationReportingProvider;
use satrs::pus::scheduler_srv::PusSchedServiceHandler;
use satrs::pus::verification::VerificationReporter;
use satrs::pus::{
EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter,
EcssTcReceiverCore, EcssTmSenderCore, MpscTcReceiver, PusPacketHandlerResult, PusServiceHelper,
TmAsVecSenderWithId, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc,
TmInSharedPoolSenderWithId,
EcssTmSenderCore, MpscTcReceiver, MpscTmAsVecSender, MpscTmInSharedPoolSenderBounded,
PusPacketHandlerResult, PusServiceHelper, PusTmAsVec, PusTmInPool, TmInSharedPoolSender,
};
use satrs::tmtc::tm_helper::SharedTmPool;
use satrs::ComponentId;
use satrs_example::config::{ComponentIdList, PUS_APID};
use satrs_example::config::components::PUS_SCHED_SERVICE;
use crate::tmtc::PusTcSourceProviderSharedPool;
@ -55,14 +50,12 @@ impl TcReleaser for mpsc::Sender<Vec<u8>> {
}
}
pub struct Pus11Wrapper<
TcReceiver: EcssTcReceiverCore,
pub struct SchedulingServiceWrapper<
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> {
pub pus_11_handler: PusService11SchedHandler<
TcReceiver,
pub pus_11_handler: PusSchedServiceHandler<
MpscTcReceiver,
TmSender,
TcInMemConverter,
VerificationReporter,
@ -73,12 +66,8 @@ pub struct Pus11Wrapper<
pub tc_releaser: Box<dyn TcReleaser + Send>,
}
impl<
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> Pus11Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
impl<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter>
SchedulingServiceWrapper<TmSender, TcInMemConverter>
{
pub fn release_tcs(&mut self) {
let releaser = |enabled: bool, info: &TcInfo, tc: &[u8]| -> bool {
@ -132,42 +121,24 @@ impl<
}
pub fn create_scheduler_service_static(
shared_tm_store: SharedTmPool,
tm_funnel_tx: mpsc::SyncSender<StoreAddr>,
verif_reporter: VerificationReporterWithSharedPoolMpscBoundedSender,
tm_sender: TmInSharedPoolSender<mpsc::SyncSender<PusTmInPool>>,
tc_releaser: PusTcSourceProviderSharedPool,
pus_sched_rx: mpsc::Receiver<EcssTcAndToken>,
sched_tc_pool: StaticMemoryPool,
) -> Pus11Wrapper<
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,
);
) -> SchedulingServiceWrapper<MpscTmInSharedPoolSenderBounded, EcssTcInSharedStoreConverter> {
let scheduler = PusScheduler::new_with_current_init_time(Duration::from_secs(5))
.expect("Creating PUS Scheduler failed");
let pus_11_handler = PusService11SchedHandler::new(
let pus_11_handler = PusSchedServiceHandler::new(
PusServiceHelper::new(
sched_srv_receiver,
sched_srv_tm_sender,
PUS_APID,
verif_reporter.clone(),
PUS_SCHED_SERVICE.raw(),
pus_sched_rx,
tm_sender,
create_verification_reporter(PUS_SCHED_SERVICE.apid),
EcssTcInSharedStoreConverter::new(tc_releaser.clone_backing_pool(), 2048),
),
scheduler,
);
Pus11Wrapper {
SchedulingServiceWrapper {
pus_11_handler,
sched_tc_pool,
releaser_buf: [0; 4096],
@ -176,40 +147,26 @@ pub fn create_scheduler_service_static(
}
pub fn create_scheduler_service_dynamic(
tm_funnel_tx: mpsc::Sender<Vec<u8>>,
verif_reporter: VerificationReporterWithVecMpscSender,
tm_funnel_tx: mpsc::Sender<PusTmAsVec>,
tc_source_sender: mpsc::Sender<Vec<u8>>,
pus_sched_rx: mpsc::Receiver<EcssTcAndToken>,
sched_tc_pool: StaticMemoryPool,
) -> Pus11Wrapper<
MpscTcReceiver,
TmAsVecSenderWithMpsc,
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,
);
) -> SchedulingServiceWrapper<MpscTmAsVecSender, EcssTcInVecConverter> {
//let sched_srv_receiver =
//MpscTcReceiver::new(PUS_SCHED_SERVICE.raw(), "PUS_11_TC_RECV", pus_sched_rx);
let scheduler = PusScheduler::new_with_current_init_time(Duration::from_secs(5))
.expect("Creating PUS Scheduler failed");
let pus_11_handler = PusService11SchedHandler::new(
let pus_11_handler = PusSchedServiceHandler::new(
PusServiceHelper::new(
sched_srv_receiver,
sched_srv_tm_sender,
PUS_APID,
verif_reporter.clone(),
PUS_SCHED_SERVICE.raw(),
pus_sched_rx,
tm_funnel_tx,
create_verification_reporter(PUS_SCHED_SERVICE.apid),
EcssTcInVecConverter::default(),
),
scheduler,
);
Pus11Wrapper {
SchedulingServiceWrapper {
pus_11_handler,
sched_tc_pool,
releaser_buf: [0; 4096],

View File

@ -1,62 +1,33 @@
use crate::pus::mode::ModeServiceWrapper;
use derive_new::new;
use satrs::{
pus::{
verification::VerificationReportingProvider, EcssTcInMemConverter, EcssTcReceiverCore,
EcssTmSenderCore,
},
pus::{EcssTcInMemConverter, EcssTmSenderCore},
spacepackets::time::{cds, TimeWriter},
};
use super::{
action::Pus8Wrapper, event::Pus5Wrapper, hk::Pus3Wrapper, scheduler::Pus11Wrapper,
test::Service17CustomWrapper, TargetedPusService,
action::ActionServiceWrapper, event::EventServiceWrapper, hk::HkServiceWrapper,
scheduler::SchedulingServiceWrapper, test::TestCustomServiceWrapper, TargetedPusService,
};
pub struct PusStack<
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> {
event_srv: Pus5Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
hk_srv_wrapper: Pus3Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
action_srv_wrapper: Pus8Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
schedule_srv: Pus11Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
test_srv: Service17CustomWrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
#[derive(new)]
pub struct PusStack<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter> {
test_srv: TestCustomServiceWrapper<TmSender, TcInMemConverter>,
hk_srv_wrapper: HkServiceWrapper<TmSender, TcInMemConverter>,
event_srv: EventServiceWrapper<TmSender, TcInMemConverter>,
action_srv_wrapper: ActionServiceWrapper<TmSender, TcInMemConverter>,
schedule_srv: SchedulingServiceWrapper<TmSender, TcInMemConverter>,
mode_srv: ModeServiceWrapper<TmSender, TcInMemConverter>,
}
impl<
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> PusStack<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
impl<TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter>
PusStack<TmSender, TcInMemConverter>
{
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) {
// Release all telecommands which reached their release time before calling the service
// handlers.
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")
.to_vec()
.unwrap();
@ -84,10 +55,15 @@ impl<
self.hk_srv_wrapper.poll_and_handle_next_tc(&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 {
// Timeout checking is only done once.
self.action_srv_wrapper.check_for_request_timeouts();
self.hk_srv_wrapper.check_for_request_timeouts();
self.mode_srv.check_for_request_timeouts();
break;
}
}

View File

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

View File

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

View File

@ -4,8 +4,9 @@ use std::{
};
use log::info;
use satrs::pus::{PusTmAsVec, PusTmInPool};
use satrs::{
pool::{PoolProvider, StoreAddr},
pool::PoolProvider,
seq_count::{CcsdsSimpleSeqCountProvider, SequenceCountProviderCore},
spacepackets::{
ecss::{tm::PusTmZeroCopyWriter, PusPacket},
@ -77,16 +78,16 @@ impl TmFunnelCommon {
pub struct TmFunnelStatic {
common: TmFunnelCommon,
shared_tm_store: SharedTmPool,
tm_funnel_rx: mpsc::Receiver<StoreAddr>,
tm_server_tx: mpsc::SyncSender<StoreAddr>,
tm_funnel_rx: mpsc::Receiver<PusTmInPool>,
tm_server_tx: mpsc::SyncSender<PusTmInPool>,
}
impl TmFunnelStatic {
pub fn new(
shared_tm_store: SharedTmPool,
sync_tm_tcp_source: SyncTcpTmSource,
tm_funnel_rx: mpsc::Receiver<StoreAddr>,
tm_server_tx: mpsc::SyncSender<StoreAddr>,
tm_funnel_rx: mpsc::Receiver<PusTmInPool>,
tm_server_tx: mpsc::SyncSender<PusTmInPool>,
) -> Self {
Self {
common: TmFunnelCommon::new(sync_tm_tcp_source),
@ -97,14 +98,14 @@ impl TmFunnelStatic {
}
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
// the CRC.
let shared_pool = self.shared_tm_store.clone_backing_pool();
let mut pool_guard = shared_pool.write().expect("Locking TM pool failed");
let mut tm_copy = Vec::new();
pool_guard
.modify(&addr, |buf| {
.modify(&pus_tm_in_pool.store_addr, |buf| {
let zero_copy_writer = PusTmZeroCopyWriter::new(buf, MIN_CDS_FIELD_LEN)
.expect("Creating TM zero copy writer failed");
self.common.apply_packet_processing(zero_copy_writer);
@ -112,7 +113,7 @@ impl TmFunnelStatic {
})
.expect("Reading TM from pool failed");
self.tm_server_tx
.send(addr)
.send(pus_tm_in_pool)
.expect("Sending TM to server failed");
// We could also do this step in the update closure, but I'd rather avoid this, could
// lead to nested locking.
@ -123,15 +124,15 @@ impl TmFunnelStatic {
pub struct TmFunnelDynamic {
common: TmFunnelCommon,
tm_funnel_rx: mpsc::Receiver<Vec<u8>>,
tm_server_tx: mpsc::Sender<Vec<u8>>,
tm_funnel_rx: mpsc::Receiver<PusTmAsVec>,
tm_server_tx: mpsc::Sender<PusTmAsVec>,
}
impl TmFunnelDynamic {
pub fn new(
sync_tm_tcp_source: SyncTcpTmSource,
tm_funnel_rx: mpsc::Receiver<Vec<u8>>,
tm_server_tx: mpsc::Sender<Vec<u8>>,
tm_funnel_rx: mpsc::Receiver<PusTmAsVec>,
tm_server_tx: mpsc::Sender<PusTmAsVec>,
) -> Self {
Self {
common: TmFunnelCommon::new(sync_tm_tcp_source),
@ -144,13 +145,13 @@ impl TmFunnelDynamic {
if let Ok(mut tm) = self.tm_funnel_rx.recv() {
// Read the TM, set sequence counter and message counter, and finally update
// 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");
self.common.apply_packet_processing(zero_copy_writer);
self.common.sync_tm_tcp_source.add_tm(&tm.packet);
self.tm_server_tx
.send(tm.clone())
.send(tm)
.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 satrs::pus::verification::std_mod::{
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender,
use satrs::pus::{
EcssTcAndToken, MpscTmAsVecSender, MpscTmInSharedPoolSenderBounded, ReceivesEcssPusTc,
};
use satrs::pus::{EcssTcAndToken, ReceivesEcssPusTc};
use satrs::spacepackets::SpHeader;
use std::sync::mpsc::{self, Receiver, SendError, Sender, SyncSender, TryRecvError};
use thiserror::Error;
@ -100,14 +99,14 @@ pub struct TcSourceTaskStatic {
shared_tc_pool: SharedTcPool,
tc_receiver: Receiver<StoreAddr>,
tc_buf: [u8; 4096],
pus_receiver: PusReceiver<VerificationReporterWithSharedPoolMpscBoundedSender>,
pus_receiver: PusReceiver<MpscTmInSharedPoolSenderBounded>,
}
impl TcSourceTaskStatic {
pub fn new(
shared_tc_pool: SharedTcPool,
tc_receiver: Receiver<StoreAddr>,
pus_receiver: PusReceiver<VerificationReporterWithSharedPoolMpscBoundedSender>,
pus_receiver: PusReceiver<MpscTmInSharedPoolSenderBounded>,
) -> Self {
Self {
shared_tc_pool,
@ -164,13 +163,13 @@ impl TcSourceTaskStatic {
// TC source components where the heap is the backing memory of the received telecommands.
pub struct TcSourceTaskDynamic {
pub tc_receiver: Receiver<Vec<u8>>,
pus_receiver: PusReceiver<VerificationReporterWithVecMpscSender>,
pus_receiver: PusReceiver<MpscTmAsVecSender>,
}
impl TcSourceTaskDynamic {
pub fn new(
tc_receiver: Receiver<Vec<u8>>,
pus_receiver: PusReceiver<VerificationReporterWithVecMpscSender>,
pus_receiver: PusReceiver<MpscTmAsVecSender>,
) -> Self {
Self {
tc_receiver,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,8 +1,7 @@
use crate::{
action::{ActionId, ActionRequest},
params::Params,
request::{GenericMessage, RequestId},
ComponentId,
request::{GenericMessage, MessageMetadata, RequestId},
};
use satrs_shared::res_code::ResultU16;
@ -57,12 +56,11 @@ pub type GenericActionReplyPus = GenericMessage<PusActionReply>;
impl GenericActionReplyPus {
pub fn new_action_reply(
request_id: RequestId,
sender_id: ComponentId,
requestor_info: MessageMetadata,
action_id: ActionId,
reply: ActionReplyVariant,
) -> 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::PusTmSecondaryHeader;
use spacepackets::ecss::{EcssEnumeration, PusError};
use spacepackets::ByteConversionError;
use spacepackets::{SpHeader, MAX_APID};
use crate::pus::EcssTmSenderCore;
@ -9,145 +10,125 @@ use crate::pus::EcssTmSenderCore;
pub use alloc_mod::EventReporter;
pub use spacepackets::ecss::event::*;
pub struct EventReporterBase {
msg_count: u16,
pub struct EventReportCreator {
apid: u16,
pub dest_id: u16,
}
impl EventReporterBase {
impl EventReportCreator {
pub fn new(apid: u16) -> Option<Self> {
if apid > MAX_APID {
return None;
}
Some(Self {
msg_count: 0,
// msg_count: 0,
dest_id: 0,
apid,
})
}
pub fn event_info(
&mut self,
buf: &mut [u8],
sender: &mut (impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
pub fn event_info<'time, 'src_data>(
&self,
src_data_buf: &'src_data mut [u8],
time_stamp: &'time [u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
aux_data: Option<&'src_data [u8]>,
) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_and_send_generic_tm(
buf,
src_data_buf,
Subservice::TmInfoReport,
sender,
time_stamp,
event_id,
aux_data,
)
}
pub fn event_low_severity(
&mut self,
buf: &mut [u8],
sender: &mut (impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
pub fn event_low_severity<'time, 'src_data>(
&self,
src_data_buf: &'src_data mut [u8],
time_stamp: &'time [u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
aux_data: Option<&'src_data [u8]>,
) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_and_send_generic_tm(
buf,
src_data_buf,
Subservice::TmLowSeverityReport,
sender,
time_stamp,
event_id,
aux_data,
)
}
pub fn event_medium_severity(
&mut self,
buf: &mut [u8],
sender: &mut (impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
pub fn event_medium_severity<'time, 'src_data>(
&self,
buf: &'src_data mut [u8],
time_stamp: &'time [u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
aux_data: Option<&'src_data [u8]>,
) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_and_send_generic_tm(
buf,
Subservice::TmMediumSeverityReport,
sender,
time_stamp,
event_id,
aux_data,
)
}
pub fn event_high_severity(
&mut self,
buf: &mut [u8],
sender: &mut (impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
pub fn event_high_severity<'time, 'src_data>(
&self,
src_data_buf: &'src_data mut [u8],
time_stamp: &'time [u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
aux_data: Option<&'src_data [u8]>,
) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_and_send_generic_tm(
buf,
src_data_buf,
Subservice::TmHighSeverityReport,
sender,
time_stamp,
event_id,
aux_data,
)
}
fn generate_and_send_generic_tm(
&mut self,
buf: &mut [u8],
fn generate_and_send_generic_tm<'time, 'src_data>(
&self,
src_data_buf: &'src_data mut [u8],
subservice: Subservice,
sender: &mut (impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
time_stamp: &'time [u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
let tm = self.generate_generic_event_tm(buf, subservice, time_stamp, event_id, aux_data)?;
sender.send_tm(tm.into())?;
self.msg_count += 1;
Ok(())
aux_data: Option<&'src_data [u8]>,
) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
self.generate_generic_event_tm(src_data_buf, subservice, time_stamp, event_id, aux_data)
}
fn generate_generic_event_tm<'a>(
&'a self,
buf: &'a mut [u8],
fn generate_generic_event_tm<'time, 'src_data>(
&self,
src_data_buf: &'src_data mut [u8],
subservice: Subservice,
time_stamp: &'a [u8],
time_stamp: &'time [u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<PusTmCreator, EcssTmtcError> {
aux_data: Option<&'src_data [u8]>,
) -> Result<PusTmCreator<'time, 'src_data>, ByteConversionError> {
let mut src_data_len = event_id.size();
if let Some(aux_data) = aux_data {
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 sec_header = PusTmSecondaryHeader::new(
5,
subservice.into(),
self.msg_count,
self.dest_id,
Some(time_stamp),
);
let sec_header =
PusTmSecondaryHeader::new(5, subservice.into(), 0, self.dest_id, Some(time_stamp));
let mut current_idx = 0;
event_id
.write_to_be_bytes(&mut buf[0..event_id.size()])
.map_err(PusError::ByteConversion)?;
event_id.write_to_be_bytes(&mut src_data_buf[0..event_id.size()])?;
current_idx += event_id.size();
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();
}
Ok(PusTmCreator::new(
&mut sp_header,
sec_header,
&buf[0..current_idx],
&src_data_buf[0..current_idx],
true,
))
}
@ -156,84 +137,95 @@ impl EventReporterBase {
#[cfg(feature = "alloc")]
mod alloc_mod {
use super::*;
use crate::ComponentId;
use alloc::vec;
use alloc::vec::Vec;
use core::cell::RefCell;
pub struct EventReporter {
source_data_buf: Vec<u8>,
pub reporter: EventReporterBase,
id: ComponentId,
// 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 {
pub fn new(apid: u16, max_event_id_and_aux_data_size: usize) -> Option<Self> {
let reporter = EventReporterBase::new(apid)?;
pub fn new(
id: ComponentId,
apid: u16,
max_event_id_and_aux_data_size: usize,
) -> Option<Self> {
let reporter = EventReportCreator::new(apid)?;
Some(Self {
source_data_buf: vec![0; max_event_id_and_aux_data_size],
reporter,
id,
source_data_buf: RefCell::new(vec![0; max_event_id_and_aux_data_size]),
report_creator: reporter,
})
}
pub fn event_info(
&mut self,
sender: &mut (impl EcssTmSenderCore + ?Sized),
&self,
sender: &(impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
self.reporter.event_info(
self.source_data_buf.as_mut_slice(),
sender,
time_stamp,
event_id,
aux_data,
)
let mut mut_buf = self.source_data_buf.borrow_mut();
let tm_creator = self
.report_creator
.event_info(mut_buf.as_mut_slice(), time_stamp, event_id, aux_data)
.map_err(PusError::ByteConversion)?;
sender.send_tm(self.id, tm_creator.into())?;
Ok(())
}
pub fn event_low_severity(
&mut self,
sender: &mut (impl EcssTmSenderCore + ?Sized),
&self,
sender: &(impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
self.reporter.event_low_severity(
self.source_data_buf.as_mut_slice(),
sender,
time_stamp,
event_id,
aux_data,
)
let mut mut_buf = self.source_data_buf.borrow_mut();
let tm_creator = self
.report_creator
.event_low_severity(mut_buf.as_mut_slice(), time_stamp, event_id, aux_data)
.map_err(PusError::ByteConversion)?;
sender.send_tm(self.id, tm_creator.into())?;
Ok(())
}
pub fn event_medium_severity(
&mut self,
sender: &mut (impl EcssTmSenderCore + ?Sized),
&self,
sender: &(impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
self.reporter.event_medium_severity(
self.source_data_buf.as_mut_slice(),
sender,
time_stamp,
event_id,
aux_data,
)
let mut mut_buf = self.source_data_buf.borrow_mut();
let tm_creator = self
.report_creator
.event_medium_severity(mut_buf.as_mut_slice(), time_stamp, event_id, aux_data)
.map_err(PusError::ByteConversion)?;
sender.send_tm(self.id, tm_creator.into())?;
Ok(())
}
pub fn event_high_severity(
&mut self,
sender: &mut (impl EcssTmSenderCore + ?Sized),
&self,
sender: &(impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
event_id: impl EcssEnumeration,
aux_data: Option<&[u8]>,
) -> Result<(), EcssTmtcError> {
self.reporter.event_high_severity(
self.source_data_buf.as_mut_slice(),
sender,
time_stamp,
event_id,
aux_data,
)
let mut mut_buf = self.source_data_buf.borrow_mut();
let tm_creator = self
.report_creator
.event_high_severity(mut_buf.as_mut_slice(), time_stamp, event_id, aux_data)
.map_err(PusError::ByteConversion)?;
sender.send_tm(self.id, tm_creator.into())?;
Ok(())
}
}
}
@ -243,7 +235,7 @@ mod tests {
use super::*;
use crate::events::{EventU32, Severity};
use crate::pus::tests::CommonTmInfo;
use crate::pus::{EcssChannel, PusTmWrapper};
use crate::pus::{ChannelWithId, PusTmVariant};
use crate::ComponentId;
use spacepackets::ByteConversionError;
use std::cell::RefCell;
@ -268,19 +260,19 @@ mod tests {
pub service_queue: RefCell<VecDeque<TmInfo>>,
}
impl EcssChannel for TestSender {
impl ChannelWithId for TestSender {
fn id(&self) -> ComponentId {
0
}
}
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 {
PusTmWrapper::InStore(_) => {
PusTmVariant::InStore(_) => {
panic!("TestSender: unexpected call with address");
}
PusTmWrapper::Direct(tm) => {
PusTmVariant::Direct(tm) => {
assert!(!tm.source_data().is_empty());
let src_data = tm.source_data();
assert!(src_data.len() >= 4);
@ -348,7 +340,7 @@ mod tests {
error_data: Option<&[u8]>,
) {
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());
let mut reporter = reporter.unwrap();
let time_stamp_empty: [u8; 7] = [0; 7];
@ -440,7 +432,7 @@ mod tests {
fn insufficient_buffer() {
let mut sender = TestSender::default();
for i in 0..3 {
let reporter = EventReporter::new(EXAMPLE_APID, i);
let reporter = EventReporter::new(0, EXAMPLE_APID, i);
assert!(reporter.is_some());
let mut reporter = reporter.unwrap();
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(
&mut self,
sender: &mut (impl EcssTmSenderCore + ?Sized),
&self,
sender: &(impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
event: EV,
aux_data: Option<&[u8]>,
@ -239,8 +239,8 @@ pub mod alloc_mod {
}
pub fn generate_pus_event_tm<Severity: HasSeverity>(
&mut self,
sender: &mut (impl EcssTmSenderCore + ?Sized),
&self,
sender: &(impl EcssTmSenderCore + ?Sized),
time_stamp: &[u8],
event: EventU32TypedSev<Severity>,
aux_data: Option<&[u8]>,
@ -257,20 +257,26 @@ pub mod alloc_mod {
#[cfg(test)]
mod tests {
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};
const INFO_EVENT: EventU32TypedSev<SeverityInfo> =
EventU32TypedSev::<SeverityInfo>::const_new(1, 0);
const LOW_SEV_EVENT: EventU32 = EventU32::const_new(Severity::LOW, 1, 5);
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<()> {
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)
}
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();
PusEventDispatcher::new(reporter, backend)
}
@ -278,10 +284,9 @@ mod tests {
#[test]
fn test_basic() {
let mut event_man = create_basic_man_1();
let (event_tx, event_rx) = mpsc::channel();
let mut sender = TmAsVecSenderWithMpsc::new(0, "test_sender", event_tx);
let (mut event_tx, event_rx) = mpsc::channel::<PusTmAsVec>();
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");
assert!(event_sent);
@ -292,13 +297,13 @@ mod tests {
#[test]
fn test_disable_event() {
let mut event_man = create_basic_man_2();
let (event_tx, event_rx) = mpsc::channel();
let mut sender = TmAsVecSenderWithMpsc::new(0, "test", event_tx);
let (event_tx, event_rx) = mpsc::channel::<PusTmAsVec>();
// let mut sender = TmAsVecSenderWithMpsc::new(0, "test", event_tx);
let res = event_man.disable_tm_for_event(&LOW_SEV_EVENT);
assert!(res.is_ok());
assert!(res.unwrap());
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");
assert!(!event_sent);
let res = event_rx.try_recv();
@ -306,7 +311,7 @@ mod tests {
assert!(matches!(res.unwrap_err(), TryRecvError::Empty));
// Check that only the low severity event was disabled
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");
assert!(event_sent);
event_rx.try_recv().expect("No info event received");
@ -315,8 +320,7 @@ mod tests {
#[test]
fn test_reenable_event() {
let mut event_man = create_basic_man_1();
let (event_tx, event_rx) = mpsc::channel();
let mut sender = TmAsVecSenderWithMpsc::new(0, "test", event_tx);
let (event_tx, event_rx) = mpsc::channel::<PusTmAsVec>();
let mut res = event_man.disable_tm_for_event_with_sev(&INFO_EVENT);
assert!(res.is_ok());
assert!(res.unwrap());
@ -324,7 +328,7 @@ mod tests {
assert!(res.is_ok());
assert!(res.unwrap());
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");
assert!(event_sent);
event_rx.try_recv().expect("No info event received");

View File

@ -13,7 +13,7 @@ use super::{
GenericRoutingError, PusServiceHelper,
};
pub struct PusService5EventHandler<
pub struct PusEventServiceHandler<
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
@ -29,7 +29,7 @@ impl<
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> PusService5EventHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
> PusEventServiceHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{
pub fn new(
service_helper: PusServiceHelper<
@ -83,7 +83,12 @@ impl<
.service_helper
.common
.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);
let partial_error = start_token.clone().err();
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::test_util::{PusTestHarness, SimplePusPacketHandler, TEST_APID};
use crate::pus::verification::{
RequestId, VerificationReporterWithSharedPoolMpscBoundedSender,
RequestId, VerificationReporter, VerificationReportingProvider,
};
use crate::pus::{GenericConversionError, MpscTcReceiver, TmInSharedPoolSenderWithBoundedMpsc};
use crate::pus::{GenericConversionError, MpscTcReceiver, MpscTmInSharedPoolSenderBounded};
use crate::{
events::EventU32,
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);
struct Pus5HandlerWithStoreTester {
common: PusServiceHandlerWithSharedStoreCommon,
handler: PusService5EventHandler<
handler: PusEventServiceHandler<
MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc,
MpscTmInSharedPoolSenderBounded,
EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender,
VerificationReporter,
>,
}
impl Pus5HandlerWithStoreTester {
pub fn new(event_request_tx: Sender<EventRequestWithToken>) -> Self {
let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new();
let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new(0);
Self {
common,
handler: PusService5EventHandler::new(srv_handler, event_request_tx),
handler: PusEventServiceHandler::new(srv_handler, event_request_tx),
}
}
}
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! {
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 check_no_tm_available(&self) -> bool;
fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId);
@ -212,7 +231,7 @@ mod tests {
impl SimplePusPacketHandler for Pus5HandlerWithStoreTester {
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)
}
}
@ -230,7 +249,8 @@ mod tests {
.write_to_be_bytes(&mut app_data)
.expect("writing test event failed");
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();
test_harness.handle_one_tc().unwrap();
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 sec_header = PusTcSecondaryHeader::new_simple(5, 200);
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();
assert!(result.is_ok());
let result = result.unwrap();
@ -306,7 +327,8 @@ mod tests {
let sec_header =
PusTcSecondaryHeader::new_simple(5, Subservice::TcEnableEventGeneration as u8);
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();
assert!(result.is_err());
let result = result.unwrap_err();

View File

@ -5,7 +5,7 @@
use crate::pool::{StoreAddr, StoreError};
use crate::pus::verification::{TcStateAccepted, TcStateToken, VerificationToken};
use crate::queue::{GenericReceiveError, GenericSendError};
use crate::request::{GenericMessage, RequestId};
use crate::request::{GenericMessage, MessageMetadata, RequestId};
use crate::ComponentId;
use core::fmt::{Display, Formatter};
use core::time::Duration;
@ -43,19 +43,19 @@ pub use std_mod::*;
use self::verification::VerificationReportingProvider;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum PusTmWrapper<'tm> {
pub enum PusTmVariant<'time, 'src_data> {
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 {
Self::InStore(value)
}
}
impl<'tm> From<PusTmCreator<'tm>> for PusTmWrapper<'tm> {
fn from(value: PusTmCreator<'tm>) -> Self {
impl<'time, 'src_data> From<PusTmCreator<'time, 'src_data>> for PusTmVariant<'time, 'src_data> {
fn from(value: PusTmCreator<'time, 'src_data>) -> Self {
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
fn id(&self) -> ComponentId;
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.
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.
@ -165,6 +165,16 @@ pub trait EcssTcSenderCore {
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,
/// storage inside a pool structure like [crate::pool::StaticMemoryPool], and storage inside a
/// `Vec<u8>` are supported.
@ -259,7 +269,7 @@ impl From<StoreError> for TryRecvTmtcError {
}
/// Generic trait for a user supplied receiver object.
pub trait EcssTcReceiverCore: EcssChannel {
pub trait EcssTcReceiverCore {
fn recv_tc(&self) -> Result<EcssTcAndToken, TryRecvTmtcError>;
}
@ -301,8 +311,7 @@ pub trait PusRequestRouter<Request> {
fn route(
&self,
request_id: RequestId,
source_id: ComponentId,
requestor_info: MessageMetadata,
target_id: ComponentId,
request: Request,
) -> 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.
fn handle_reply(
&mut self,
caller_id: ComponentId,
reply: &GenericMessage<ReplyType>,
active_request: &ActiveRequestInfo,
tm_sender: &impl EcssTmSenderCore,
verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8],
tm_sender: &impl EcssTmSenderCore,
) -> Result<bool, Self::Error>;
fn handle_unrequested_reply(
&mut self,
caller_id: ComponentId,
reply: &GenericMessage<ReplyType>,
tm_sender: &impl EcssTmSenderCore,
) -> Result<(), Self::Error>;
@ -331,10 +342,11 @@ pub trait PusReplyHandler<ActiveRequestInfo: ActiveRequestProvider, ReplyType> {
/// Handle the timeout of an active request.
fn handle_request_timeout(
&mut self,
caller_id: ComponentId,
active_request: &ActiveRequestInfo,
tm_sender: &impl EcssTmSenderCore,
verification_handler: &impl VerificationReportingProvider,
time_stamp: &[u8],
tm_sender: &impl EcssTmSenderCore,
) -> Result<(), Self::Error>;
}
@ -445,10 +457,12 @@ pub mod alloc_mod {
type Error;
fn convert(
&mut self,
caller_id: ComponentId,
token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader,
time_stamp: &[u8],
tm_sender: &(impl EcssTmSenderCore + ?Sized),
verif_reporter: &impl VerificationReportingProvider,
time_stamp: &[u8],
) -> Result<(ActiveRequestInfo, Request), Self::Error>;
}
@ -647,8 +661,8 @@ pub mod std_mod {
};
use crate::pus::verification::{TcStateAccepted, VerificationToken};
use crate::pus::{
EcssChannel, EcssTcAndToken, EcssTcReceiverCore, EcssTmSenderCore, EcssTmtcError,
GenericReceiveError, GenericSendError, PusTmWrapper, TryRecvTmtcError,
EcssTcAndToken, EcssTcReceiverCore, EcssTmSenderCore, EcssTmtcError, GenericReceiveError,
GenericSendError, PusTmVariant, TryRecvTmtcError,
};
use crate::tmtc::tm_helper::SharedTmPool;
use crate::ComponentId;
@ -670,54 +684,82 @@ pub mod std_mod {
use super::verification::{TcStateToken, VerificationReportingProvider};
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 {
fn from(_: mpsc::SendError<StoreAddr>) -> Self {
Self::Send(GenericSendError::RxDisconnected)
}
}
impl EcssTmSenderCore for mpsc::Sender<StoreAddr> {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
impl EcssTmSenderCore for mpsc::Sender<PusTmInPool> {
fn send_tm(&self, source_id: ComponentId, tm: PusTmVariant) -> Result<(), EcssTmtcError> {
match tm {
PusTmWrapper::InStore(addr) => self
.send(addr)
PusTmVariant::InStore(store_addr) => self
.send(PusTmInPool {
source_id,
store_addr,
})
.map_err(|_| GenericSendError::RxDisconnected)?,
PusTmWrapper::Direct(_) => return Err(EcssTmtcError::CantSendDirectTm),
PusTmVariant::Direct(_) => return Err(EcssTmtcError::CantSendDirectTm),
};
Ok(())
}
}
impl EcssTmSenderCore for mpsc::SyncSender<StoreAddr> {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
impl EcssTmSenderCore for mpsc::SyncSender<PusTmInPool> {
fn send_tm(&self, source_id: ComponentId, tm: PusTmVariant) -> Result<(), EcssTmtcError> {
match tm {
PusTmWrapper::InStore(addr) => self
.try_send(addr)
PusTmVariant::InStore(store_addr) => self
.try_send(PusTmInPool {
source_id,
store_addr,
})
.map_err(|e| EcssTmtcError::Send(e.into()))?,
PusTmWrapper::Direct(_) => return Err(EcssTmtcError::CantSendDirectTm),
PusTmVariant::Direct(_) => return Err(EcssTmtcError::CantSendDirectTm),
};
Ok(())
}
}
impl EcssTmSenderCore for mpsc::Sender<Vec<u8>> {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
#[derive(Debug)]
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 {
PusTmWrapper::InStore(addr) => return Err(EcssTmtcError::CantSendAddr(addr)),
PusTmWrapper::Direct(tm) => self
.send(tm.to_vec()?)
PusTmVariant::InStore(addr) => return Err(EcssTmtcError::CantSendAddr(addr)),
PusTmVariant::Direct(tm) => self
.send(PusTmAsVec {
source_id,
packet: tm.to_vec()?,
})
.map_err(|e| EcssTmtcError::Send(e.into()))?,
};
Ok(())
}
}
impl EcssTmSenderCore for mpsc::SyncSender<Vec<u8>> {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
pub type MpscTmAsVecSenderBounded = mpsc::SyncSender<PusTmAsVec>;
impl EcssTmSenderCore for MpscTmAsVecSenderBounded {
fn send_tm(&self, source_id: ComponentId, tm: PusTmVariant) -> Result<(), EcssTmtcError> {
match tm {
PusTmWrapper::InStore(addr) => return Err(EcssTmtcError::CantSendAddr(addr)),
PusTmWrapper::Direct(tm) => self
.send(tm.to_vec()?)
PusTmVariant::InStore(addr) => return Err(EcssTmtcError::CantSendAddr(addr)),
PusTmVariant::Direct(tm) => self
.send(PusTmAsVec {
source_id,
packet: tm.to_vec()?,
})
.map_err(|e| EcssTmtcError::Send(e.into()))?,
};
Ok(())
@ -725,67 +767,52 @@ pub mod std_mod {
}
#[derive(Clone)]
pub struct TmInSharedPoolSenderWithId<Sender: EcssTmSenderCore> {
channel_id: ComponentId,
name: &'static str,
pub struct TmInSharedPoolSender<Sender: EcssTmSenderCore> {
shared_tm_store: SharedTmPool,
sender: Sender,
}
impl<Sender: EcssTmSenderCore> EcssChannel for TmInSharedPoolSenderWithId<Sender> {
fn id(&self) -> ComponentId {
self.channel_id
}
fn name(&self) -> &'static str {
self.name
}
}
impl<Sender: EcssTmSenderCore> TmInSharedPoolSenderWithId<Sender> {
pub fn send_direct_tm(&self, tm: PusTmCreator) -> Result<(), EcssTmtcError> {
impl<Sender: EcssTmSenderCore> TmInSharedPoolSender<Sender> {
pub fn send_direct_tm(
&self,
source_id: ComponentId,
tm: PusTmCreator,
) -> Result<(), EcssTmtcError> {
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> {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
if let PusTmWrapper::Direct(tm) = tm {
return self.send_direct_tm(tm);
impl<Sender: EcssTmSenderCore> EcssTmSenderCore for TmInSharedPoolSender<Sender> {
fn send_tm(&self, source_id: ComponentId, tm: PusTmVariant) -> Result<(), EcssTmtcError> {
if let PusTmVariant::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> {
pub fn new(
id: ComponentId,
name: &'static str,
shared_tm_store: SharedTmPool,
sender: Sender,
) -> Self {
impl<Sender: EcssTmSenderCore> TmInSharedPoolSender<Sender> {
pub fn new(shared_tm_store: SharedTmPool, sender: Sender) -> Self {
Self {
channel_id: id,
name,
shared_tm_store,
sender,
}
}
}
pub type TmInSharedPoolSenderWithMpsc = TmInSharedPoolSenderWithId<mpsc::Sender<StoreAddr>>;
pub type TmInSharedPoolSenderWithBoundedMpsc =
TmInSharedPoolSenderWithId<mpsc::SyncSender<StoreAddr>>;
pub type MpscTmInSharedPoolSender = TmInSharedPoolSender<mpsc::Sender<PusTmInPool>>;
pub type MpscTmInSharedPoolSenderBounded = TmInSharedPoolSender<mpsc::SyncSender<PusTmInPool>>;
/*
/// 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
/// of this class can not deal with store addresses, so it is assumed that is is always
/// going to be called with direct packets.
#[derive(Clone)]
pub struct TmAsVecSenderWithId<Sender: EcssTmSenderCore> {
id: ComponentId,
name: &'static str,
// id: ComponentId,
//name: &'static str,
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 {
self.id
}
@ -811,58 +838,34 @@ pub mod std_mod {
}
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)
}
}
pub type TmAsVecSenderWithMpsc = TmAsVecSenderWithId<mpsc::Sender<Vec<u8>>>;
pub type TmAsVecSenderWithBoundedMpsc = TmAsVecSenderWithId<mpsc::SyncSender<Vec<u8>>>;
*/
pub struct MpscTcReceiver {
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
}
}
pub type MpscTcReceiver = mpsc::Receiver<EcssTcAndToken>;
impl EcssTcReceiverCore for MpscTcReceiver {
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::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")]
pub mod cb_mod {
use super::*;
use crossbeam_channel as cb;
pub type TmInSharedPoolSenderWithCrossbeam =
TmInSharedPoolSenderWithId<cb::Sender<StoreAddr>>;
pub type TmInSharedPoolSenderWithCrossbeam = TmInSharedPoolSender<cb::Sender<PusTmInPool>>;
impl From<cb::SendError<StoreAddr>> for EcssTmtcError {
fn from(_: cb::SendError<StoreAddr>) -> Self {
@ -881,65 +884,44 @@ pub mod std_mod {
}
}
impl EcssTmSenderCore for cb::Sender<StoreAddr> {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
impl EcssTmSenderCore for cb::Sender<PusTmInPool> {
fn send_tm(
&self,
source_id: ComponentId,
tm: PusTmVariant,
) -> Result<(), EcssTmtcError> {
match tm {
PusTmWrapper::InStore(addr) => self
.try_send(addr)
PusTmVariant::InStore(addr) => self
.try_send(PusTmInPool {
source_id,
store_addr: addr,
})
.map_err(|e| EcssTmtcError::Send(e.into()))?,
PusTmWrapper::Direct(_) => return Err(EcssTmtcError::CantSendDirectTm),
PusTmVariant::Direct(_) => return Err(EcssTmtcError::CantSendDirectTm),
};
Ok(())
}
}
impl EcssTmSenderCore for cb::Sender<Vec<u8>> {
fn send_tm(&self, tm: PusTmWrapper) -> Result<(), EcssTmtcError> {
impl EcssTmSenderCore for cb::Sender<PusTmAsVec> {
fn send_tm(
&self,
source_id: ComponentId,
tm: PusTmVariant,
) -> Result<(), EcssTmtcError> {
match tm {
PusTmWrapper::InStore(addr) => return Err(EcssTmtcError::CantSendAddr(addr)),
PusTmWrapper::Direct(tm) => self
.send(tm.to_vec()?)
PusTmVariant::InStore(addr) => return Err(EcssTmtcError::CantSendAddr(addr)),
PusTmVariant::Direct(tm) => self
.send(PusTmAsVec {
source_id,
packet: tm.to_vec()?,
})
.map_err(|e| EcssTmtcError::Send(e.into()))?,
};
Ok(())
}
}
pub struct CrossbeamTcReceiver {
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())),
)),
})
}
}
pub type CrossbeamTcReceiver = cb::Receiver<EcssTcAndToken>;
}
/// 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,
VerificationReporter: VerificationReportingProvider,
> {
pub id: ComponentId,
pub tc_receiver: TcReceiver,
pub tm_sender: TmSender,
pub tm_apid: u16,
pub verif_reporter: VerificationReporter,
}
@ -1327,23 +1309,31 @@ pub mod std_mod {
> PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{
pub fn new(
id: ComponentId,
tc_receiver: TcReceiver,
tm_sender: TmSender,
tm_apid: u16,
verification_handler: VerificationReporter,
tc_in_mem_converter: TcInMemConverter,
) -> Self {
Self {
common: PusServiceBase {
id,
tc_receiver,
tm_sender,
tm_apid,
verif_reporter: verification_handler,
},
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
/// 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
@ -1378,6 +1368,9 @@ pub mod std_mod {
pub fn verif_reporter(&self) -> &VerificationReporter {
&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 {
&self.tc_in_mem_converter
@ -1388,50 +1381,47 @@ pub mod std_mod {
}
}
pub type PusServiceHelperDynWithMpsc<TcInMemConverter, VerificationReporter> = PusServiceHelper<
MpscTcReceiver,
TmAsVecSenderWithMpsc,
TcInMemConverter,
VerificationReporter,
>;
pub type PusServiceHelperDynWithMpsc<TcInMemConverter, VerificationReporter> =
PusServiceHelper<MpscTcReceiver, MpscTmAsVecSender, TcInMemConverter, VerificationReporter>;
pub type PusServiceHelperDynWithBoundedMpsc<TcInMemConverter, VerificationReporter> =
PusServiceHelper<
MpscTcReceiver,
TmAsVecSenderWithBoundedMpsc,
MpscTmAsVecSenderBounded,
TcInMemConverter,
VerificationReporter,
>;
pub type PusServiceHelperStaticWithMpsc<TcInMemConverter, VerificationReporter> =
PusServiceHelper<
MpscTcReceiver,
TmInSharedPoolSenderWithMpsc,
MpscTmInSharedPoolSender,
TcInMemConverter,
VerificationReporter,
>;
pub type PusServiceHelperStaticWithBoundedMpsc<TcInMemConverter, VerificationReporter> =
PusServiceHelper<
MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc,
MpscTmInSharedPoolSenderBounded,
TcInMemConverter,
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 {
return Err(
PusError::ByteConversion(ByteConversionError::ToSliceTooSmall {
found: cap,
expected: len,
})
.into(),
);
return Err(ByteConversionError::ToSliceTooSmall {
found: cap,
expected: len,
});
}
Ok(())
}
#[cfg(any(feature = "test_util", test))]
pub mod test_util {
use crate::request::UniqueApidTargetId;
use spacepackets::ecss::{tc::PusTcCreator, tm::PusTmReader};
use super::{
@ -1440,9 +1430,13 @@ pub mod test_util {
};
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 {
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 check_no_tm_available(&self) -> bool;
fn check_next_verification_tm(
@ -1471,22 +1465,16 @@ pub mod tests {
use spacepackets::ecss::{PusPacket, WritablePusPacket};
use spacepackets::CcsdsPacket;
use crate::pool::{
PoolProvider, SharedStaticMemoryPool, StaticMemoryPool, StaticPoolConfig, StoreAddr,
};
use crate::pus::verification::RequestId;
use crate::pool::{PoolProvider, SharedStaticMemoryPool, StaticMemoryPool, StaticPoolConfig};
use crate::pus::verification::{RequestId, VerificationReporter};
use crate::tmtc::tm_helper::SharedTmPool;
use crate::ComponentId;
use super::test_util::TEST_APID;
use super::test_util::{TEST_APID, TEST_COMPONENT_ID};
use super::verification::std_mod::{
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender,
};
use super::verification::test_util::{SharedVerificationMap, TestVerificationReporter};
use super::verification::test_util::TestVerificationReporter;
use super::verification::{
TcStateAccepted, VerificationReporterCfg, VerificationReporterWithSender,
VerificationReportingProvider, VerificationToken,
TcStateAccepted, VerificationReporterCfg, VerificationReportingProvider, VerificationToken,
};
use super::*;
@ -1515,20 +1503,19 @@ pub mod tests {
/// Common fields for a PUS service test harness.
pub struct PusServiceHandlerWithSharedStoreCommon {
pus_buf: [u8; 2048],
pus_buf: RefCell<[u8; 2048]>,
tm_buf: [u8; 2048],
tc_pool: SharedStaticMemoryPool,
tm_pool: SharedTmPool,
tc_sender: mpsc::SyncSender<EcssTcAndToken>,
tm_receiver: mpsc::Receiver<StoreAddr>,
verification_handler: VerificationReporterWithSharedPoolMpscBoundedSender,
tm_receiver: mpsc::Receiver<PusTmInPool>,
}
pub type PusServiceHelperStatic = PusServiceHelper<
MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc,
MpscTmInSharedPoolSenderBounded,
EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender,
VerificationReporter,
>;
impl PusServiceHandlerWithSharedStoreCommon {
@ -1536,7 +1523,7 @@ pub mod tests {
/// [PusServiceHandler] which might be required for a specific PUS service handler.
///
/// 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 tc_pool = StaticMemoryPool::new(pool_cfg.clone());
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 (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 verification_handler =
VerificationReporterWithSharedPoolMpscBoundedSender::new(&verif_cfg, verif_sender);
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 verification_handler = VerificationReporter::new(&verif_cfg);
let test_srv_tm_sender = TmInSharedPoolSender::new(shared_tm_pool.clone(), tm_tx);
let in_store_converter =
EcssTcInSharedStoreConverter::new(shared_tc_pool.clone(), 2048);
(
Self {
pus_buf: [0; 2048],
pus_buf: RefCell::new([0; 2048]),
tm_buf: [0; 2048],
tc_pool: shared_tc_pool,
tm_pool: shared_tm_pool,
tc_sender: test_srv_tc_tx,
tm_receiver: tm_rx,
verification_handler: verification_handler.clone(),
},
PusServiceHelper::new(
test_srv_tc_receiver,
id,
test_srv_tc_rx,
test_srv_tm_sender,
TEST_APID,
verification_handler,
in_store_converter,
),
)
}
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();
let tc_size = tc.write_to_bytes(&mut self.pus_buf).unwrap();
pub fn send_tc(&self, token: &VerificationToken<TcStateAccepted>, tc: &PusTcCreator) {
let mut mut_buf = self.pus_buf.borrow_mut();
let tc_size = tc.write_to_bytes(mut_buf.as_mut_slice()).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);
// Send accepted TC to test service handler.
self.tc_sender
.send(EcssTcAndToken::new(addr, token))
.send(EcssTcAndToken::new(addr, *token))
.expect("sending tc failed");
token
}
pub fn read_next_tm(&mut self) -> PusTmReader<'_> {
let next_msg = self.tm_receiver.try_recv();
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_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);
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) {
let next_msg = self.tm_receiver.try_recv();
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_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;
assert_eq!(PusPacket::service(&tm), 1);
assert_eq!(PusPacket::subservice(&tm), subservice);
@ -1629,56 +1601,49 @@ pub mod tests {
}
}
pub struct PusServiceHandlerWithVecCommon<VerificationReporter: VerificationReportingProvider> {
current_tm: Option<alloc::vec::Vec<u8>>,
pub struct PusServiceHandlerWithVecCommon {
current_tm: Option<Vec<u8>>,
tc_sender: mpsc::Sender<EcssTcAndToken>,
tm_receiver: mpsc::Receiver<alloc::vec::Vec<u8>>,
pub verification_handler: VerificationReporter,
tm_receiver: mpsc::Receiver<PusTmAsVec>,
}
pub type PusServiceHelperDynamic = PusServiceHelper<
MpscTcReceiver,
TmAsVecSenderWithMpsc,
MpscTmAsVecSender,
EcssTcInVecConverter,
VerificationReporterWithVecMpscSender,
TestVerificationReporter,
>;
impl PusServiceHandlerWithVecCommon<VerificationReporterWithVecMpscSender> {
pub fn new_with_standard_verif_reporter() -> (Self, PusServiceHelperDynamic) {
impl PusServiceHandlerWithVecCommon {
pub fn new_with_standard_verif_reporter(
id: ComponentId,
) -> (Self, PusServiceHelperDynamic) {
let (test_srv_tc_tx, test_srv_tc_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();
(
Self {
current_tm: None,
tc_sender: test_srv_tc_tx,
tm_receiver: tm_rx,
verification_handler: verification_handler.clone(),
},
PusServiceHelper::new(
test_srv_tc_receiver,
test_srv_tm_sender,
TEST_APID,
verification_handler,
id,
test_srv_tc_rx,
tm_tx,
TestVerificationReporter::default(),
in_store_converter,
),
)
}
}
impl PusServiceHandlerWithVecCommon<TestVerificationReporter> {
impl PusServiceHandlerWithVecCommon {
pub fn new_with_test_verif_sender() -> (
Self,
PusServiceHelper<
MpscTcReceiver,
TmAsVecSenderWithMpsc,
MpscTmAsVecSender,
EcssTcInVecConverter,
TestVerificationReporter,
>,
@ -1686,22 +1651,19 @@ pub mod tests {
let (test_srv_tc_tx, test_srv_tc_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 shared_verif_map = SharedVerificationMap::default();
let verification_handler = TestVerificationReporter::new(shared_verif_map);
let verification_handler = TestVerificationReporter::default();
(
Self {
current_tm: None,
tc_sender: test_srv_tc_tx,
tm_receiver: tm_rx,
verification_handler: verification_handler.clone(),
//verification_handler: verification_handler.clone(),
},
PusServiceHelper::new(
test_srv_tc_receiver,
test_srv_tm_sender,
TEST_APID,
TEST_COMPONENT_ID.raw(),
test_srv_tc_rx,
tm_tx,
verification_handler,
in_store_converter,
),
@ -1709,29 +1671,21 @@ pub mod tests {
}
}
impl<VerificationReporter: VerificationReportingProvider>
PusServiceHandlerWithVecCommon<VerificationReporter>
{
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();
impl PusServiceHandlerWithVecCommon {
pub fn send_tc(&self, token: &VerificationToken<TcStateAccepted>, tc: &PusTcCreator) {
// Send accepted TC to test service handler.
self.tc_sender
.send(EcssTcAndToken::new(
TcInMemory::Vec(tc.to_vec().expect("pus tc conversion to vec failed")),
token,
*token,
))
.expect("sending tc failed");
token
}
pub fn read_next_tm(&mut self) -> PusTmReader<'_> {
let next_msg = self.tm_receiver.try_recv();
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)
.unwrap()
.0
@ -1749,7 +1703,7 @@ pub mod tests {
let next_msg = self.tm_receiver.try_recv();
assert!(next_msg.is_ok());
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::subservice(&tm), subservice);
assert_eq!(tm.apid(), TEST_APID);

View File

@ -31,139 +31,7 @@ pub mod alloc_mod {}
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
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(())
}
}
*/
}
pub mod std_mod {}
#[cfg(test)]
mod tests {
@ -175,7 +43,7 @@ mod tests {
ModeAndSubmode, ModeReply, ModeReplySender, ModeRequest, ModeRequestSender,
ModeRequestorAndHandlerMpsc, ModeRequestorMpsc,
},
request::GenericMessage,
request::{GenericMessage, MessageMetadata},
};
const TEST_COMPONENT_ID_0: u64 = 5;
@ -196,24 +64,23 @@ mod tests {
.send_mode_request(request_id, TEST_COMPONENT_ID_1, sent_request)
.expect("send failed");
let request = request_receiver.recv().expect("recv failed");
assert_eq!(request.request_id, 2);
assert_eq!(request.sender_id, TEST_COMPONENT_ID_0);
assert_eq!(request.request_id(), 2);
assert_eq!(request.sender_id(), TEST_COMPONENT_ID_0);
assert_eq!(request.message, sent_request);
// Send a reply and verify it arrives at the requestor.
let mode_reply = ModeReply::ModeReply(ModeAndSubmode::new(1, 5));
reply_sender
.send(GenericMessage::new(
request_id,
TEST_COMPONENT_ID_1,
MessageMetadata::new(request_id, TEST_COMPONENT_ID_1),
mode_reply,
))
.expect("send failed");
let reply = mode_requestor.try_recv_mode_reply().expect("recv failed");
assert!(reply.is_some());
let reply = reply.unwrap();
assert_eq!(reply.sender_id, TEST_COMPONENT_ID_1);
assert_eq!(reply.request_id, 2);
assert_eq!(reply.sender_id(), TEST_COMPONENT_ID_1);
assert_eq!(reply.request_id(), 2);
assert_eq!(reply.message, mode_reply);
}
@ -252,8 +119,8 @@ mod tests {
.expect("send failed");
let request = request_receiver_channel_1.recv().expect("recv failed");
assert_eq!(request.request_id, 2);
assert_eq!(request.sender_id, TEST_COMPONENT_ID_0);
assert_eq!(request.request_id(), 2);
assert_eq!(request.sender_id(), TEST_COMPONENT_ID_0);
assert_eq!(request.message, ModeRequest::ReadMode);
}
@ -272,13 +139,16 @@ mod tests {
// Send a request and verify it arrives at the receiver.
let request_id = 2;
let sent_reply = ModeReply::ModeInfo(ModeAndSubmode::new(3, 5));
let sent_reply = ModeReply::ModeReply(ModeAndSubmode::new(3, 5));
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");
let reply = reply_receiver_channel_2.recv().expect("recv failed");
assert_eq!(reply.request_id, 2);
assert_eq!(reply.sender_id, TEST_COMPONENT_ID_0);
assert_eq!(reply.request_id(), 2);
assert_eq!(reply.sender_id(), TEST_COMPONENT_ID_0);
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::verification::{
VerificationReporterWithSharedPoolMpscBoundedSender,
VerificationReporterWithSharedPoolMpscSender, VerificationReporterWithVecMpscBoundedSender,
VerificationReporterWithVecMpscSender, VerificationReportingProvider,
};
use super::verification::{VerificationReporter, VerificationReportingProvider};
use super::{
EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiverCore,
EcssTmSenderCore, MpscTcReceiver, PusServiceHelper, TmAsVecSenderWithBoundedMpsc,
TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithMpsc,
EcssTmSenderCore, MpscTcReceiver, MpscTmInSharedPoolSender, MpscTmInSharedPoolSenderBounded,
PusServiceHelper, PusTmAsVec,
};
use crate::pool::PoolProvider;
use crate::pus::{PusPacketHandlerResult, PusPacketHandlingError};
use alloc::string::ToString;
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)
/// 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
/// [Self::scheduler] and [Self::scheduler_mut] function and then use the scheduler API to release
/// telecommands when applicable.
pub struct PusService11SchedHandler<
pub struct PusSchedServiceHandler<
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
@ -42,13 +39,7 @@ impl<
VerificationReporter: VerificationReportingProvider,
Scheduler: PusSchedulerProvider,
>
PusService11SchedHandler<
TcReceiver,
TmSender,
TcInMemConverter,
VerificationReporter,
Scheduler,
>
PusSchedServiceHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter, Scheduler>
{
pub fn new(
service_helper: PusServiceHelper<
@ -101,14 +92,24 @@ impl<
let start_token = self
.service_helper
.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");
self.scheduler.enable();
if self.scheduler.is_enabled() {
self.service_helper
.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");
} else {
return Err(PusPacketHandlingError::Other(
@ -120,14 +121,24 @@ impl<
let start_token = self
.service_helper
.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");
self.scheduler.disable();
if !self.scheduler.is_enabled() {
self.service_helper
.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");
} else {
return Err(PusPacketHandlingError::Other(
@ -139,7 +150,12 @@ impl<
let start_token = self
.service_helper
.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");
self.scheduler
@ -148,7 +164,12 @@ impl<
self.service_helper
.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");
}
scheduling::Subservice::TcInsertActivity => {
@ -156,17 +177,27 @@ impl<
.service_helper
.common
.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");
// let mut pool = self.sched_tc_pool.write().expect("locking pool failed");
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");
self.service_helper
.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");
}
_ => {
@ -187,38 +218,38 @@ impl<
}
/// Helper type definition for a PUS 11 handler with a dynamic TMTC memory backend and regular
/// mpsc queues.
pub type PusService11SchedHandlerDynWithMpsc<PusScheduler> = PusService11SchedHandler<
pub type PusService11SchedHandlerDynWithMpsc<PusScheduler> = PusSchedServiceHandler<
MpscTcReceiver,
TmAsVecSenderWithMpsc,
mpsc::Sender<PusTmAsVec>,
EcssTcInVecConverter,
VerificationReporterWithVecMpscSender,
VerificationReporter,
PusScheduler,
>;
/// Helper type definition for a PUS 11 handler with a dynamic TMTC memory backend and bounded MPSC
/// queues.
pub type PusService11SchedHandlerDynWithBoundedMpsc<PusScheduler> = PusService11SchedHandler<
pub type PusService11SchedHandlerDynWithBoundedMpsc<PusScheduler> = PusSchedServiceHandler<
MpscTcReceiver,
TmAsVecSenderWithBoundedMpsc,
mpsc::SyncSender<PusTmAsVec>,
EcssTcInVecConverter,
VerificationReporterWithVecMpscBoundedSender,
VerificationReporter,
PusScheduler,
>;
/// Helper type definition for a PUS 11 handler with a shared store TMTC memory backend and regular
/// mpsc queues.
pub type PusService11SchedHandlerStaticWithMpsc<PusScheduler> = PusService11SchedHandler<
pub type PusService11SchedHandlerStaticWithMpsc<PusScheduler> = PusSchedServiceHandler<
MpscTcReceiver,
TmInSharedPoolSenderWithMpsc,
MpscTmInSharedPoolSender,
EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscSender,
VerificationReporter,
PusScheduler,
>;
/// Helper type definition for a PUS 11 handler with a shared store TMTC memory backend and bounded
/// mpsc queues.
pub type PusService11SchedHandlerStaticWithBoundedMpsc<PusScheduler> = PusService11SchedHandler<
pub type PusService11SchedHandlerStaticWithBoundedMpsc<PusScheduler> = PusSchedServiceHandler<
MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc,
MpscTmInSharedPoolSenderBounded,
EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender,
VerificationReporter,
PusScheduler,
>;
@ -226,7 +257,8 @@ pub type PusService11SchedHandlerStaticWithBoundedMpsc<PusScheduler> = PusServic
mod tests {
use crate::pool::{StaticMemoryPool, StaticPoolConfig};
use crate::pus::test_util::{PusTestHarness, TEST_APID};
use crate::pus::verification::VerificationReporterWithSharedPoolMpscBoundedSender;
use crate::pus::verification::{VerificationReporter, VerificationReportingProvider};
use crate::pus::{
scheduler::{self, PusSchedulerProvider, TcInfo},
tests::PusServiceHandlerWithSharedStoreCommon,
@ -234,8 +266,8 @@ mod tests {
EcssTcInSharedStoreConverter,
};
use crate::pus::{
MpscTcReceiver, PusPacketHandlerResult, PusPacketHandlingError,
TmInSharedPoolSenderWithBoundedMpsc,
MpscTcReceiver, MpscTmInSharedPoolSenderBounded, PusPacketHandlerResult,
PusPacketHandlingError,
};
use alloc::collections::VecDeque;
use delegate::delegate;
@ -249,15 +281,15 @@ mod tests {
time::cds,
};
use super::PusService11SchedHandler;
use super::PusSchedServiceHandler;
struct Pus11HandlerWithStoreTester {
common: PusServiceHandlerWithSharedStoreCommon,
handler: PusService11SchedHandler<
handler: PusSchedServiceHandler<
MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc,
MpscTmInSharedPoolSenderBounded,
EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender,
VerificationReporter,
TestScheduler,
>,
sched_tc_pool: StaticMemoryPool,
@ -268,25 +300,39 @@ mod tests {
let test_scheduler = TestScheduler::default();
let pool_cfg = StaticPoolConfig::new(alloc::vec![(16, 16), (8, 32), (4, 64)], false);
let sched_tc_pool = StaticMemoryPool::new(pool_cfg.clone());
let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new();
let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new(0);
Self {
common,
handler: PusService11SchedHandler::new(srv_handler, test_scheduler),
handler: PusSchedServiceHandler::new(srv_handler, test_scheduler),
sched_tc_pool,
}
}
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
.poll_and_handle_next_tc(&time_stamp, &mut self.sched_tc_pool)
}
}
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! {
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 check_no_tm_available(&self) -> bool;
fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId);
@ -304,7 +350,7 @@ mod tests {
}
impl PusSchedulerProvider for TestScheduler {
type TimeProvider = cds::TimeProvider;
type TimeProvider = cds::CdsTime;
fn reset(
&mut self,
@ -330,7 +376,7 @@ mod tests {
fn insert_unwrapped_and_stored_tc(
&mut self,
_time_stamp: spacepackets::time::UnixTimestamp,
_time_stamp: spacepackets::time::UnixTime,
info: crate::pus::scheduler::TcInfo,
) -> Result<(), crate::pus::scheduler::ScheduleError> {
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 tc_header = PusTcSecondaryHeader::new_simple(11, subservice as u8);
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 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
.handler
.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 ping_tc = PusTcCreator::new(&mut reply_header, sec_header, &[], true);
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 written_len = stamper.write_to_bytes(&mut sched_app_data).unwrap();
let ping_raw = ping_tc.to_vec().expect("generating raw tc failed");
@ -406,7 +453,8 @@ mod tests {
&sched_app_data[..written_len],
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();
test_harness.handle_one_tc().unwrap();

View File

@ -1,20 +1,17 @@
use crate::pus::{
PartialPusHandlingError, PusPacketHandlerResult, PusPacketHandlingError, PusTmWrapper,
PartialPusHandlingError, PusPacketHandlerResult, PusPacketHandlingError, PusTmAsVec,
PusTmInPool, PusTmVariant,
};
use spacepackets::ecss::tm::{PusTmCreator, PusTmSecondaryHeader};
use spacepackets::ecss::PusPacket;
use spacepackets::SpHeader;
use std::sync::mpsc;
use super::verification::{
VerificationReporterWithSharedPoolMpscBoundedSender,
VerificationReporterWithSharedPoolMpscSender, VerificationReporterWithVecMpscBoundedSender,
VerificationReporterWithVecMpscSender, VerificationReportingProvider,
};
use super::verification::{VerificationReporter, VerificationReportingProvider};
use super::{
EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiverCore,
EcssTmSenderCore, GenericConversionError, MpscTcReceiver, PusServiceHelper,
TmAsVecSenderWithBoundedMpsc, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc,
TmInSharedPoolSenderWithMpsc,
EcssTmSenderCore, GenericConversionError, MpscTcReceiver, MpscTmInSharedPoolSender,
MpscTmInSharedPoolSenderBounded, PusServiceHelper,
};
/// This is a helper class for [std] environments to handle generic PUS 17 (test service) packets.
@ -68,7 +65,12 @@ impl<
let result = self
.service_helper
.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);
let start_token = if let Ok(result) = result {
Some(result)
@ -78,14 +80,14 @@ impl<
};
// Sequence count will be handled centrally in TM funnel.
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 ping_reply = PusTmCreator::new(&mut reply_header, tc_header, &[], true);
let result = self
.service_helper
.common
.tm_sender
.send_tm(PusTmWrapper::Direct(ping_reply))
.send_tm(self.service_helper.id(), PusTmVariant::Direct(ping_reply))
.map_err(PartialPusHandlingError::TmSend);
if let Err(err) = result {
partial_error = Some(err);
@ -95,7 +97,12 @@ impl<
if self
.service_helper
.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()
{
partial_error = Some(PartialPusHandlingError::Verification)
@ -120,33 +127,33 @@ impl<
/// mpsc queues.
pub type PusService17TestHandlerDynWithMpsc = PusService17TestHandler<
MpscTcReceiver,
TmAsVecSenderWithMpsc,
mpsc::Sender<PusTmAsVec>,
EcssTcInVecConverter,
VerificationReporterWithVecMpscSender,
VerificationReporter,
>;
/// Helper type definition for a PUS 17 handler with a dynamic TMTC memory backend and bounded MPSC
/// queues.
pub type PusService17TestHandlerDynWithBoundedMpsc = PusService17TestHandler<
MpscTcReceiver,
TmAsVecSenderWithBoundedMpsc,
mpsc::SyncSender<PusTmInPool>,
EcssTcInVecConverter,
VerificationReporterWithVecMpscBoundedSender,
VerificationReporter,
>;
/// Helper type definition for a PUS 17 handler with a shared store TMTC memory backend and regular
/// mpsc queues.
pub type PusService17TestHandlerStaticWithMpsc = PusService17TestHandler<
MpscTcReceiver,
TmInSharedPoolSenderWithMpsc,
MpscTmInSharedPoolSender,
EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscSender,
VerificationReporter,
>;
/// Helper type definition for a PUS 17 handler with a shared store TMTC memory backend and bounded
/// mpsc queues.
pub type PusService17TestHandlerStaticWithBoundedMpsc = PusService17TestHandler<
MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc,
MpscTmInSharedPoolSenderBounded,
EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender,
VerificationReporter,
>;
#[cfg(test)]
@ -155,16 +162,17 @@ mod tests {
use crate::pus::tests::{
PusServiceHandlerWithSharedStoreCommon, PusServiceHandlerWithVecCommon,
};
use crate::pus::verification::std_mod::{
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender,
use crate::pus::verification::test_util::TestVerificationReporter;
use crate::pus::verification::{
RequestId, VerificationReporter, VerificationReportingProvider,
};
use crate::pus::verification::RequestId;
use crate::pus::verification::{TcStateAccepted, VerificationToken};
use crate::pus::{
EcssTcInSharedStoreConverter, EcssTcInVecConverter, GenericConversionError, MpscTcReceiver,
PusPacketHandlerResult, PusPacketHandlingError, TmAsVecSenderWithMpsc,
TmInSharedPoolSenderWithBoundedMpsc,
MpscTmAsVecSender, MpscTmInSharedPoolSenderBounded, PusPacketHandlerResult,
PusPacketHandlingError,
};
use crate::ComponentId;
use delegate::delegate;
use spacepackets::ecss::tc::{PusTcCreator, PusTcSecondaryHeader};
use spacepackets::ecss::tm::PusTmReader;
@ -178,15 +186,15 @@ mod tests {
common: PusServiceHandlerWithSharedStoreCommon,
handler: PusService17TestHandler<
MpscTcReceiver,
TmInSharedPoolSenderWithBoundedMpsc,
MpscTmInSharedPoolSenderBounded,
EcssTcInSharedStoreConverter,
VerificationReporterWithSharedPoolMpscBoundedSender,
VerificationReporter,
>,
}
impl Pus17HandlerWithStoreTester {
pub fn new() -> Self {
let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new();
pub fn new(id: ComponentId) -> Self {
let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new(id);
let pus_17_handler = PusService17TestHandler::new(srv_handler);
Self {
common,
@ -196,10 +204,24 @@ mod tests {
}
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! {
to self.common {
fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>;
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_next_verification_tm(
&self,
@ -211,25 +233,25 @@ mod tests {
}
impl SimplePusPacketHandler for Pus17HandlerWithStoreTester {
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)
}
}
struct Pus17HandlerWithVecTester {
common: PusServiceHandlerWithVecCommon<VerificationReporterWithVecMpscSender>,
common: PusServiceHandlerWithVecCommon,
handler: PusService17TestHandler<
MpscTcReceiver,
TmAsVecSenderWithMpsc,
MpscTmAsVecSender,
EcssTcInVecConverter,
VerificationReporterWithVecMpscSender,
TestVerificationReporter,
>,
}
impl Pus17HandlerWithVecTester {
pub fn new() -> Self {
pub fn new(id: ComponentId) -> Self {
let (common, srv_handler) =
PusServiceHandlerWithVecCommon::new_with_standard_verif_reporter();
PusServiceHandlerWithVecCommon::new_with_standard_verif_reporter(id);
Self {
common,
handler: PusService17TestHandler::new(srv_handler),
@ -238,9 +260,23 @@ mod tests {
}
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! {
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 check_no_tm_available(&self) -> bool;
fn check_next_verification_tm(
@ -253,7 +289,7 @@ mod tests {
}
impl SimplePusPacketHandler for Pus17HandlerWithVecTester {
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)
}
}
@ -263,7 +299,8 @@ mod tests {
let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap();
let sec_header = PusTcSecondaryHeader::new_simple(17, 1);
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 result = test_harness.handle_one_tc();
assert!(result.is_ok());
@ -288,19 +325,19 @@ mod tests {
#[test]
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);
}
#[test]
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);
}
#[test]
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();
assert!(result.is_ok());
let result = result.unwrap();
@ -312,11 +349,12 @@ mod tests {
#[test]
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 sec_header = PusTcSecondaryHeader::new_simple(3, 1);
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();
assert!(result.is_err());
let error = result.unwrap_err();
@ -332,11 +370,12 @@ mod tests {
#[test]
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 sec_header = PusTcSecondaryHeader::new_simple(17, 200);
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();
assert!(result.is_ok());
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;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct TargetAndApidId {
pub struct UniqueApidTargetId {
pub apid: Apid,
pub target: u32,
pub unique_id: u32,
}
impl TargetAndApidId {
impl UniqueApidTargetId {
pub const fn new(apid: Apid, target: u32) -> Self {
Self { apid, target }
Self {
apid,
unique_id: target,
}
}
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()
}
@ -61,49 +64,78 @@ impl TargetAndApidId {
}
}
impl From<u64> for TargetAndApidId {
impl From<u64> for UniqueApidTargetId {
fn from(raw: u64) -> Self {
Self {
apid: (raw >> 32) as u16,
target: raw as u32,
unique_id: raw as u32,
}
}
}
impl From<TargetAndApidId> for u64 {
fn from(target_and_apid_id: TargetAndApidId) -> Self {
impl From<UniqueApidTargetId> for u64 {
fn from(target_and_apid_id: UniqueApidTargetId) -> Self {
target_and_apid_id.raw()
}
}
impl fmt::Display for TargetAndApidId {
impl fmt::Display for UniqueApidTargetId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"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
/// with a request using a [RequestId].
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct GenericMessage<MSG> {
pub request_id: RequestId,
pub sender_id: ComponentId,
pub requestor_info: MessageMetadata,
pub message: 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 {
request_id,
sender_id,
requestor_info,
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.
@ -186,8 +218,7 @@ pub mod alloc_mod {
pub fn send_message(
&self,
request_id: RequestId,
local_channel_id: ComponentId,
requestor_info: MessageMetadata,
target_channel_id: ComponentId,
message: MSG,
) -> Result<(), GenericTargetedMessagingError> {
@ -196,45 +227,12 @@ pub mod alloc_mod {
.0
.get(&target_channel_id)
.unwrap()
.send(GenericMessage::new(request_id, local_channel_id, message));
.send(GenericMessage::new(requestor_info, message));
}
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 local_channel_id: ComponentId,
pub message_sender_map: MessageSenderMap<TO, S>,
@ -265,13 +263,12 @@ pub mod alloc_mod {
pub fn send_message(
&self,
request_id: RequestId,
target_channel_id: ComponentId,
target_id: ComponentId,
message: TO,
) -> Result<(), GenericTargetedMessagingError> {
self.message_sender_map.send_message(
request_id,
self.local_channel_id_generic(),
target_channel_id,
MessageMetadata::new(request_id, self.local_channel_id_generic()),
target_id,
message,
)
}
@ -390,9 +387,12 @@ mod tests {
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_1: u64 = 2;
@ -400,15 +400,15 @@ mod tests {
#[test]
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.target, 0x01);
assert_eq!(id.full_target_id(), id.raw());
assert_eq!(id.unique_id, 0x01);
assert_eq!(id.id(), id.raw());
assert_eq!(u64::from(id), 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.full_target_id(), (0x111 << 32) | 0x01);
assert_eq!(id.id(), (0x111 << 32) | 0x01);
let string = id.to_string();
assert_eq!(
string,
@ -421,9 +421,9 @@ mod tests {
let mut sp_header = SpHeader::tc_unseg(0x111, 5, 0).unwrap();
let app_data = 1_u32.to_be_bytes();
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.target, 1);
assert_eq!(id.unique_id, 1);
}
#[test]
@ -431,7 +431,7 @@ mod tests {
let mut sp_header = SpHeader::tc_unseg(0x111, 5, 0).unwrap();
let sec_header = PusTcSecondaryHeader::new_simple(17, 1);
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());
let error = error.unwrap_err();
if let ByteConversionError::FromSliceTooSmall { found, expected } = error {
@ -449,14 +449,17 @@ mod tests {
let receiver = MessageReceiverWithId::new(TEST_CHANNEL_ID_0, receiver);
let request_id = 5;
sender
.send(GenericMessage::new(request_id, TEST_CHANNEL_ID_1, 5))
.send(GenericMessage::new(
MessageMetadata::new(request_id, TEST_CHANNEL_ID_1),
5,
))
.unwrap();
let reply = receiver.try_recv_message().unwrap();
assert!(reply.is_some());
assert_eq!(receiver.local_channel_id(), TEST_CHANNEL_ID_0);
let reply = reply.unwrap();
assert_eq!(reply.request_id, request_id);
assert_eq!(reply.sender_id, TEST_CHANNEL_ID_1);
assert_eq!(reply.requestor_info.request_id, request_id);
assert_eq!(reply.requestor_info.sender_id, TEST_CHANNEL_ID_1);
assert_eq!(reply.message, 5);
}
@ -490,31 +493,43 @@ mod tests {
fn test_sender_map() {
let (sender0, receiver0) = 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_2, sender1);
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");
let mut reply = receiver0.recv().expect("receiving message failed");
assert_eq!(reply.request_id, 1);
assert_eq!(reply.sender_id, TEST_CHANNEL_ID_0);
assert_eq!(reply.request_id(), 1);
assert_eq!(reply.sender_id(), TEST_CHANNEL_ID_0);
assert_eq!(reply.message, 5);
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");
reply = receiver1.recv().expect("receiving message failed");
assert_eq!(reply.request_id, 2);
assert_eq!(reply.sender_id, TEST_CHANNEL_ID_0);
assert_eq!(reply.request_id(), 2);
assert_eq!(reply.sender_id(), TEST_CHANNEL_ID_0);
assert_eq!(reply.message, 10);
}
#[test]
fn test_sender_map_target_does_not_exist() {
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);
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());
let error = result.unwrap_err();
if let GenericTargetedMessagingError::Send(GenericSendError::TargetDoesNotExist(target)) =
@ -528,12 +543,20 @@ mod tests {
#[test]
fn test_sender_map_queue_full() {
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
.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");
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());
let error = result.unwrap_err();
if let GenericTargetedMessagingError::Send(GenericSendError::QueueFull(capacity)) = error {
@ -546,10 +569,14 @@ mod tests {
#[test]
fn test_sender_map_queue_receiver_disconnected() {
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);
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());
let error = result.unwrap_err();
if let GenericTargetedMessagingError::Send(GenericSendError::RxDisconnected) = error {

View File

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

View File

@ -1,5 +1,5 @@
use spacepackets::ecss::tm::{PusTmCreator, PusTmSecondaryHeader};
use spacepackets::time::cds::TimeProvider;
use spacepackets::time::cds::CdsTime;
use spacepackets::time::TimeWriter;
use spacepackets::SpHeader;
@ -68,7 +68,7 @@ impl PusTmWithCdsShortHelper {
source_data: &'a [u8],
seq_count: u16,
) -> 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();
self.create_pus_tm_common(service, subservice, source_data, seq_count)
}
@ -78,7 +78,7 @@ impl PusTmWithCdsShortHelper {
service: u8,
subservice: u8,
source_data: &'a [u8],
stamper: &TimeProvider,
stamper: &CdsTime,
seq_count: u16,
) -> PusTmCreator {
stamper.write_to_bytes(&mut self.cds_short_buf).unwrap();
@ -100,14 +100,14 @@ impl PusTmWithCdsShortHelper {
#[cfg(test)]
mod tests {
use spacepackets::{ecss::PusPacket, time::cds::TimeProvider, CcsdsPacket};
use spacepackets::{ecss::PusPacket, time::cds::CdsTime, CcsdsPacket};
use super::PusTmWithCdsShortHelper;
#[test]
fn test_helper_with_stamper() {
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);
assert_eq!(tm.service(), 17);
assert_eq!(tm.subservice(), 1);

View File

@ -2,7 +2,7 @@
use core::mem::size_of;
use serde::{Deserialize, Serialize};
use spacepackets::ecss::{PfcReal, PfcUnsigned, Ptc};
use spacepackets::time::cds::TimeProvider;
use spacepackets::time::cds::CdsTime;
use spacepackets::time::{CcsdsTimeProvider, TimeWriter};
enum NumOfParamsInfo {
@ -36,7 +36,7 @@ struct TestMgmHkWithIndividualValidity {
#[derive(Serialize, Deserialize)]
struct TestMgmHkWithGroupValidity {
last_valid_stamp: TimeProvider,
last_valid_stamp: CdsTime,
valid: bool,
temp: f32,
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:
// Use a JSON format
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,
temp: 20.0,
mgm_vals: [0x1f1f, 0x2f2f, 0x3f3f],

View File

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

View File

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

View File

@ -3,10 +3,11 @@ pub mod crossbeam_test {
use hashbrown::HashMap;
use satrs::pool::{PoolProvider, PoolProviderWithGuards, StaticMemoryPool, StaticPoolConfig};
use satrs::pus::verification::{
FailParams, RequestId, VerificationReporterCfg, VerificationReporterWithSender,
FailParams, RequestId, VerificationReporter, VerificationReporterCfg,
VerificationReportingProvider,
};
use satrs::pus::TmInSharedPoolSenderWithCrossbeam;
use satrs::request::UniqueApidTargetId;
use satrs::tmtc::tm_helper::SharedTmPool;
use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader};
use spacepackets::ecss::tm::PusTmReader;
@ -17,6 +18,8 @@ pub mod crossbeam_test {
use std::time::Duration;
const TEST_APID: u16 = 0x03;
const TEST_ID: TargetAndApidId = TargetAndApidId::new(TEST_APID, 0x05);
const FIXED_STAMP: [u8; 7] = [0; 7];
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_1 = shared_tc_pool_0.clone();
let (tx, rx) = crossbeam_channel::bounded(10);
let sender = TmInSharedPoolSenderWithCrossbeam::new(
0,
"verif_sender",
shared_tm_pool.clone(),
tx.clone(),
);
let mut reporter_with_sender_0 = VerificationReporterWithSender::new(&cfg, sender);
let sender_0 = TmInSharedPoolSenderWithCrossbeam::new(shared_tm_pool.clone(), tx.clone());
let sender_1 = sender_0.clone();
let mut reporter_with_sender_0 = VerificationReporter::new(&cfg);
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
// tread.
@ -93,24 +92,36 @@ pub mod crossbeam_test {
let token = reporter_with_sender_0.add_tc_with_req_id(req_id_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");
// Do some start handling here
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");
// Do some step handling here
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");
// Finish up
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");
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");
});
@ -128,15 +139,15 @@ pub mod crossbeam_test {
let (tc, _) = PusTcReader::new(&tc_buf[0..tc_len]).unwrap();
let token = reporter_with_sender_1.add_tc(&tc);
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");
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");
let fail_code = EcssEnumU16::new(2);
let params = FailParams::new_no_fail_data(&FIXED_STAMP, &fail_code);
reporter_with_sender_1
.completion_failure(started_token, params)
.completion_failure(TEST_ID.raw(), &sender_1, started_token, params)
.expect("Completion success failed");
});
@ -145,14 +156,14 @@ pub mod crossbeam_test {
let mut tm_buf: [u8; 1024] = [0; 1024];
let mut verif_map = HashMap::new();
while packet_counter < PACKETS_SENT {
let verif_addr = rx
let tm_in_pool = rx
.recv_timeout(Duration::from_millis(50))
.expect("Packet reception timeout");
let tm_len;
let shared_tm_store = shared_tm_pool.clone_backing_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
.read(&mut tm_buf)
.expect("Error reading TM slice");