this might finally work..
Some checks failed
Rust/sat-rs/pipeline/pr-main There was a failure building this commit

This commit is contained in:
2024-03-21 13:06:46 +01:00
parent 6873a8f2a7
commit 309d0101a0
19 changed files with 453 additions and 664 deletions

View File

@ -1,7 +1,4 @@
use crate::{
pus::verification::{TcStateAccepted, VerificationToken},
TargetId,
};
use crate::ComponentId;
pub type CollectionIntervalFactor = u32;
pub type UniqueId = u32;
@ -16,25 +13,15 @@ pub enum HkRequest {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TargetedHkRequest {
pub target_id: TargetId,
pub target_id: ComponentId,
pub hk_request: HkRequest,
}
impl TargetedHkRequest {
pub fn new(target_id: TargetId, hk_request: HkRequest) -> Self {
pub fn new(target_id: ComponentId, hk_request: HkRequest) -> Self {
Self {
target_id,
hk_request,
}
}
}
pub trait PusHkRequestRouter {
type Error;
fn route(
&self,
target_id: TargetId,
hk_request: HkRequest,
token: VerificationToken<TcStateAccepted>,
) -> Result<(), Self::Error>;
}

View File

@ -35,7 +35,6 @@ pub mod hal;
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
pub mod mode_tree;
pub mod objects;
pub mod pool;
pub mod power;
pub mod pus;
@ -55,5 +54,5 @@ pub use spacepackets;
pub use queue::ChannelId;
/// Generic target ID type.
pub type TargetId = u64;
/// Generic component ID type.
pub type ComponentId = u64;

View File

@ -13,7 +13,7 @@ pub use std_mod::*;
use crate::{
queue::GenericTargetedMessagingError,
request::{GenericMessage, MessageReceiver, MessageReceiverWithId, RequestId},
ChannelId, TargetId,
ChannelId, ComponentId,
};
pub type Mode = u32;
@ -77,19 +77,19 @@ impl ModeAndSubmode {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TargetedModeCommand {
pub address: TargetId,
pub address: ComponentId,
pub mode_submode: ModeAndSubmode,
}
impl TargetedModeCommand {
pub const fn new(address: TargetId, mode_submode: ModeAndSubmode) -> Self {
pub const fn new(address: ComponentId, mode_submode: ModeAndSubmode) -> Self {
Self {
address,
mode_submode,
}
}
pub fn address(&self) -> TargetId {
pub fn address(&self) -> ComponentId {
self.address
}
@ -118,7 +118,7 @@ pub enum ModeRequest {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TargetedModeRequest {
target_id: TargetId,
target_id: ComponentId,
mode_request: ModeRequest,
}

View File

@ -1,308 +0,0 @@
//! # Module providing addressable object support and a manager for them
//!
//! Each addressable object can be identified using an [object ID][ObjectId].
//! The [system object][ManagedSystemObject] trait also allows storing these objects into the
//! [object manager][ObjectManager]. They can then be retrieved and casted back to a known type
//! using the object ID.
//!
//! # Examples
//!
//! ```rust
//! use std::any::Any;
//! use std::error::Error;
//! use satrs::objects::{ManagedSystemObject, ObjectId, ObjectManager, SystemObject};
//!
//! struct ExampleSysObj {
//! id: ObjectId,
//! dummy: u32,
//! was_initialized: bool,
//! }
//!
//! impl ExampleSysObj {
//! fn new(id: ObjectId, dummy: u32) -> ExampleSysObj {
//! ExampleSysObj {
//! id,
//! dummy,
//! was_initialized: false,
//! }
//! }
//! }
//!
//! impl SystemObject for ExampleSysObj {
//! type Error = ();
//! fn get_object_id(&self) -> &ObjectId {
//! &self.id
//! }
//!
//! fn initialize(&mut self) -> Result<(), Self::Error> {
//! self.was_initialized = true;
//! Ok(())
//! }
//! }
//!
//! impl ManagedSystemObject for ExampleSysObj {}
//!
//! let mut obj_manager = ObjectManager::default();
//! let obj_id = ObjectId { id: 0, name: "Example 0"};
//! let example_obj = ExampleSysObj::new(obj_id, 42);
//! obj_manager.insert(Box::new(example_obj));
//! let obj_back_casted: Option<&ExampleSysObj> = obj_manager.get_ref(&obj_id);
//! let example_obj = obj_back_casted.unwrap();
//! assert_eq!(example_obj.id, obj_id);
//! assert_eq!(example_obj.dummy, 42);
//! ```
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
pub use alloc_mod::*;
#[cfg(feature = "alloc")]
use downcast_rs::Downcast;
#[cfg(feature = "alloc")]
use hashbrown::HashMap;
#[cfg(feature = "std")]
use std::error::Error;
use crate::TargetId;
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub struct ObjectId {
pub id: TargetId,
pub name: &'static str,
}
#[cfg(feature = "alloc")]
pub mod alloc_mod {
use super::*;
/// Each object which is stored inside the [object manager][ObjectManager] needs to implemented
/// this trait
pub trait SystemObject: Downcast {
type Error;
fn get_object_id(&self) -> &ObjectId;
fn initialize(&mut self) -> Result<(), Self::Error>;
}
downcast_rs::impl_downcast!(SystemObject assoc Error);
pub trait ManagedSystemObject: SystemObject + Send {}
downcast_rs::impl_downcast!(ManagedSystemObject assoc Error);
/// Helper module to manage multiple [ManagedSystemObjects][ManagedSystemObject] by mapping them
/// using an [object ID][ObjectId]
#[cfg(feature = "alloc")]
pub struct ObjectManager<E> {
obj_map: HashMap<ObjectId, Box<dyn ManagedSystemObject<Error = E>>>,
}
#[cfg(feature = "alloc")]
impl<E: 'static> Default for ObjectManager<E> {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "alloc")]
impl<E: 'static> ObjectManager<E> {
pub fn new() -> Self {
ObjectManager {
obj_map: HashMap::new(),
}
}
pub fn insert(&mut self, sys_obj: Box<dyn ManagedSystemObject<Error = E>>) -> bool {
let obj_id = sys_obj.get_object_id();
if self.obj_map.contains_key(obj_id) {
return false;
}
self.obj_map.insert(*obj_id, sys_obj).is_none()
}
/// Initializes all System Objects in the hash map and returns the number of successful
/// initializations
pub fn initialize(&mut self) -> Result<u32, Box<dyn Error>> {
let mut init_success = 0;
for val in self.obj_map.values_mut() {
if val.initialize().is_ok() {
init_success += 1
}
}
Ok(init_success)
}
/// Retrieve a reference to an object stored inside the manager. The type to retrieve needs to
/// be explicitly passed as a generic parameter or specified on the left hand side of the
/// expression.
pub fn get_ref<T: ManagedSystemObject<Error = E>>(&self, key: &ObjectId) -> Option<&T> {
self.obj_map.get(key).and_then(|o| o.downcast_ref::<T>())
}
/// Retrieve a mutable reference to an object stored inside the manager. The type to retrieve
/// needs to be explicitly passed as a generic parameter or specified on the left hand side
/// of the expression.
pub fn get_mut<T: ManagedSystemObject<Error = E>>(
&mut self,
key: &ObjectId,
) -> Option<&mut T> {
self.obj_map
.get_mut(key)
.and_then(|o| o.downcast_mut::<T>())
}
}
}
#[cfg(test)]
mod tests {
use crate::objects::{ManagedSystemObject, ObjectId, ObjectManager, SystemObject};
use std::boxed::Box;
use std::string::String;
use std::sync::{Arc, Mutex};
use std::thread;
struct ExampleSysObj {
id: ObjectId,
dummy: u32,
was_initialized: bool,
}
impl ExampleSysObj {
fn new(id: ObjectId, dummy: u32) -> ExampleSysObj {
ExampleSysObj {
id,
dummy,
was_initialized: false,
}
}
}
impl SystemObject for ExampleSysObj {
type Error = ();
fn get_object_id(&self) -> &ObjectId {
&self.id
}
fn initialize(&mut self) -> Result<(), Self::Error> {
self.was_initialized = true;
Ok(())
}
}
impl ManagedSystemObject for ExampleSysObj {}
struct OtherExampleObject {
id: ObjectId,
string: String,
was_initialized: bool,
}
impl SystemObject for OtherExampleObject {
type Error = ();
fn get_object_id(&self) -> &ObjectId {
&self.id
}
fn initialize(&mut self) -> Result<(), Self::Error> {
self.was_initialized = true;
Ok(())
}
}
impl ManagedSystemObject for OtherExampleObject {}
#[test]
fn test_obj_manager_simple() {
let mut obj_manager = ObjectManager::default();
let expl_obj_id = ObjectId {
id: 0,
name: "Example 0",
};
let example_obj = ExampleSysObj::new(expl_obj_id, 42);
assert!(obj_manager.insert(Box::new(example_obj)));
let res = obj_manager.initialize();
assert!(res.is_ok());
assert_eq!(res.unwrap(), 1);
let obj_back_casted: Option<&ExampleSysObj> = obj_manager.get_ref(&expl_obj_id);
assert!(obj_back_casted.is_some());
let expl_obj_back_casted = obj_back_casted.unwrap();
assert_eq!(expl_obj_back_casted.dummy, 42);
assert!(expl_obj_back_casted.was_initialized);
let second_obj_id = ObjectId {
id: 12,
name: "Example 1",
};
let second_example_obj = OtherExampleObject {
id: second_obj_id,
string: String::from("Hello Test"),
was_initialized: false,
};
assert!(obj_manager.insert(Box::new(second_example_obj)));
let res = obj_manager.initialize();
assert!(res.is_ok());
assert_eq!(res.unwrap(), 2);
let obj_back_casted: Option<&OtherExampleObject> = obj_manager.get_ref(&second_obj_id);
assert!(obj_back_casted.is_some());
let expl_obj_back_casted = obj_back_casted.unwrap();
assert_eq!(expl_obj_back_casted.string, String::from("Hello Test"));
assert!(expl_obj_back_casted.was_initialized);
let existing_obj_id = ObjectId {
id: 12,
name: "Example 1",
};
let invalid_obj = OtherExampleObject {
id: existing_obj_id,
string: String::from("Hello Test"),
was_initialized: false,
};
assert!(!obj_manager.insert(Box::new(invalid_obj)));
}
#[test]
fn object_man_threaded() {
let obj_manager = Arc::new(Mutex::new(ObjectManager::new()));
let expl_obj_id = ObjectId {
id: 0,
name: "Example 0",
};
let example_obj = ExampleSysObj::new(expl_obj_id, 42);
let second_obj_id = ObjectId {
id: 12,
name: "Example 1",
};
let second_example_obj = OtherExampleObject {
id: second_obj_id,
string: String::from("Hello Test"),
was_initialized: false,
};
let mut obj_man_handle = obj_manager.lock().expect("Mutex lock failed");
assert!(obj_man_handle.insert(Box::new(example_obj)));
assert!(obj_man_handle.insert(Box::new(second_example_obj)));
let res = obj_man_handle.initialize();
std::mem::drop(obj_man_handle);
assert!(res.is_ok());
assert_eq!(res.unwrap(), 2);
let obj_man_0 = obj_manager.clone();
let jh0 = thread::spawn(move || {
let locked_man = obj_man_0.lock().expect("Mutex lock failed");
let obj_back_casted: Option<&ExampleSysObj> = locked_man.get_ref(&expl_obj_id);
assert!(obj_back_casted.is_some());
let expl_obj_back_casted = obj_back_casted.unwrap();
assert_eq!(expl_obj_back_casted.dummy, 42);
assert!(expl_obj_back_casted.was_initialized);
std::mem::drop(locked_man)
});
let jh1 = thread::spawn(move || {
let locked_man = obj_manager.lock().expect("Mutex lock failed");
let obj_back_casted: Option<&OtherExampleObject> = locked_man.get_ref(&second_obj_id);
assert!(obj_back_casted.is_some());
let expl_obj_back_casted = obj_back_casted.unwrap();
assert_eq!(expl_obj_back_casted.string, String::from("Hello Test"));
assert!(expl_obj_back_casted.was_initialized);
std::mem::drop(locked_man)
});
jh0.join().expect("Joining thread 0 failed");
jh1.join().expect("Joining thread 1 failed");
}
}

View File

@ -2,7 +2,7 @@ use crate::{
action::{ActionId, ActionRequest},
params::Params,
request::{GenericMessage, RequestId},
ChannelId, TargetId,
ChannelId,
};
use super::{verification::VerificationToken, ActivePusRequestStd, ActiveRequestProvider};
@ -141,7 +141,10 @@ pub mod alloc_mod {
pub mod std_mod {
use std::sync::mpsc;
use crate::pus::{verification, DefaultActiveRequestMap};
use crate::{
pus::{verification, DefaultActiveRequestMap},
ComponentId,
};
use super::*;
@ -154,7 +157,7 @@ pub mod std_mod {
impl ActiveRequestProvider for ActivePusActionRequestStd {
delegate! {
to self.common {
fn target_id(&self) -> TargetId;
fn target_id(&self) -> ComponentId;
fn token(&self) -> VerificationToken<verification::TcStateStarted>;
fn has_timed_out(&self) -> bool;
fn timeout(&self) -> core::time::Duration;
@ -165,7 +168,7 @@ pub mod std_mod {
impl ActivePusActionRequestStd {
pub fn new(
action_id: ActionId,
target_id: TargetId,
target_id: ComponentId,
token: VerificationToken<verification::TcStateStarted>,
timeout: core::time::Duration,
) -> Self {

View File

@ -2,12 +2,16 @@ use crate::events::EventU32;
use crate::pus::event_man::{EventRequest, EventRequestWithToken};
use crate::pus::verification::TcStateToken;
use crate::pus::{PartialPusHandlingError, PusPacketHandlerResult, PusPacketHandlingError};
use crate::queue::GenericSendError;
use spacepackets::ecss::event::Subservice;
use spacepackets::ecss::PusPacket;
use std::sync::mpsc::Sender;
use super::verification::VerificationReportingProvider;
use super::{EcssTcInMemConverter, EcssTcReceiverCore, EcssTmSenderCore, PusServiceHelper};
use super::{
EcssTcInMemConverter, EcssTcReceiverCore, EcssTmSenderCore, GenericConversionError,
GenericRoutingError, PusServiceHelper,
};
pub struct PusService5EventHandler<
TcReceiver: EcssTcReceiverCore,
@ -51,10 +55,10 @@ impl<
return Ok(PusPacketHandlerResult::Empty);
}
let ecss_tc_and_token = possible_packet.unwrap();
let tc = self
.service_helper
.tc_in_mem_converter
.convert_ecss_tc_in_memory_to_reader(&ecss_tc_and_token.tc_in_memory)?;
self.service_helper
.tc_in_mem_converter_mut()
.cache(&ecss_tc_and_token.tc_in_memory)?;
let tc = self.service_helper.tc_in_mem_converter().convert()?;
let subservice = tc.subservice();
let srv = Subservice::try_from(subservice);
if srv.is_err() {
@ -63,55 +67,63 @@ impl<
ecss_tc_and_token.token,
));
}
let handle_enable_disable_request = |enable: bool| {
if tc.user_data().len() < 4 {
return Err(PusPacketHandlingError::NotEnoughAppData {
expected: 4,
found: tc.user_data().len(),
});
}
let user_data = tc.user_data();
let event_u32 = EventU32::from(u32::from_be_bytes(user_data[0..4].try_into().unwrap()));
let start_token = self
.service_helper
.common
.verification_handler
.start_success(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();
if let Ok(start_token) = start_token {
token = start_token.into();
}
let event_req_with_token = if enable {
EventRequestWithToken {
request: EventRequest::Enable(event_u32),
token,
let handle_enable_disable_request =
|enable: bool| -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
if tc.user_data().len() < 4 {
return Err(GenericConversionError::NotEnoughAppData {
expected: 4,
found: tc.user_data().len(),
}
.into());
}
} else {
EventRequestWithToken {
request: EventRequest::Disable(event_u32),
token,
let user_data = tc.user_data();
let event_u32 =
EventU32::from(u32::from_be_bytes(user_data[0..4].try_into().unwrap()));
let start_token = self
.service_helper
.common
.verif_reporter
.start_success(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();
if let Ok(start_token) = start_token {
token = start_token.into();
}
let event_req_with_token = if enable {
EventRequestWithToken {
request: EventRequest::Enable(event_u32),
token,
}
} else {
EventRequestWithToken {
request: EventRequest::Disable(event_u32),
token,
}
};
self.event_request_tx
.send(event_req_with_token)
.map_err(|_| {
PusPacketHandlingError::RequestRouting(GenericRoutingError::Send(
GenericSendError::RxDisconnected,
))
})?;
if let Some(partial_error) = partial_error {
return Ok(PusPacketHandlerResult::RequestHandledPartialSuccess(
partial_error,
));
}
Ok(PusPacketHandlerResult::RequestHandled)
};
self.event_request_tx
.send(event_req_with_token)
.map_err(|_| {
PusPacketHandlingError::Other("Forwarding event request failed".into())
})?;
if let Some(partial_error) = partial_error {
return Ok(PusPacketHandlerResult::RequestHandledPartialSuccess(
partial_error,
));
}
Ok(PusPacketHandlerResult::RequestHandled)
};
match srv.unwrap() {
Subservice::TmInfoReport
| Subservice::TmLowSeverityReport
| Subservice::TmMediumSeverityReport
| Subservice::TmHighSeverityReport => {
return Err(PusPacketHandlingError::InvalidSubservice(tc.subservice()))
return Err(PusPacketHandlingError::RequestConversion(
GenericConversionError::WrongService(tc.subservice()),
))
}
Subservice::TcEnableEventGeneration => {
handle_enable_disable_request(true)?;
@ -151,7 +163,7 @@ mod tests {
use crate::pus::verification::{
RequestId, VerificationReporterWithSharedPoolMpscBoundedSender,
};
use crate::pus::{MpscTcReceiver, TmInSharedPoolSenderWithBoundedMpsc};
use crate::pus::{GenericConversionError, MpscTcReceiver, TmInSharedPoolSenderWithBoundedMpsc};
use crate::{
events::EventU32,
pus::{
@ -298,7 +310,10 @@ mod tests {
let result = test_harness.handle_one_tc();
assert!(result.is_err());
let result = result.unwrap_err();
if let PusPacketHandlingError::NotEnoughAppData { expected, found } = result {
if let PusPacketHandlingError::RequestConversion(
GenericConversionError::NotEnoughAppData { expected, found },
) = result
{
assert_eq!(expected, 4);
assert_eq!(found, 3);
} else {

View File

@ -6,7 +6,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::{ChannelId, TargetId};
use crate::{ChannelId, ComponentId};
use core::fmt::{Display, Formatter};
use core::time::Duration;
#[cfg(feature = "alloc")]
@ -287,7 +287,7 @@ pub trait ActiveRequestMapProvider<V>: Sized {
}
pub trait ActiveRequestProvider {
fn target_id(&self) -> TargetId;
fn target_id(&self) -> ComponentId;
fn token(&self) -> VerificationToken<TcStateStarted>;
fn has_timed_out(&self) -> bool;
fn timeout(&self) -> Duration;
@ -300,25 +300,17 @@ pub trait PusRequestRouter<Request> {
fn route(
&self,
target_id: TargetId,
target_id: ComponentId,
request: Request,
token: VerificationToken<TcStateAccepted>,
token: VerificationToken<TcStateStarted>,
) -> Result<(), Self::Error>;
fn handle_error(
&self,
target_id: TargetId,
token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader,
error: Self::Error,
time_stamp: &[u8],
verif_reporter: &impl VerificationReportingProvider,
);
}
pub trait PusReplyHandler<ActiveRequestInfo: ActiveRequestProvider, ReplyType> {
type Error;
/// This function handles a reply for a given PUS request and returns whether that request
/// is finished. A finished PUS request will be removed from the active request map.
fn handle_reply(
&mut self,
reply: &GenericMessage<ReplyType>,
@ -334,6 +326,7 @@ pub trait PusReplyHandler<ActiveRequestInfo: ActiveRequestProvider, ReplyType> {
tm_sender: &impl EcssTmSenderCore,
) -> Result<(), Self::Error>;
/// Handle the timeout of an active request.
fn handle_request_timeout(
&mut self,
active_request: &ActiveRequestInfo,
@ -656,13 +649,14 @@ pub mod std_mod {
GenericReceiveError, GenericSendError, PusTmWrapper, TryRecvTmtcError,
};
use crate::tmtc::tm_helper::SharedTmPool;
use crate::{ChannelId, TargetId};
use crate::{ChannelId, ComponentId};
use alloc::vec::Vec;
use core::time::Duration;
use spacepackets::ecss::tc::PusTcReader;
use spacepackets::ecss::tm::PusTmCreator;
use spacepackets::ecss::{PusError, WritablePusPacket};
use spacepackets::ecss::WritablePusPacket;
use spacepackets::time::StdTimestampError;
use spacepackets::ByteConversionError;
use std::string::String;
use std::sync::mpsc;
use std::sync::mpsc::TryRecvError;
@ -1059,7 +1053,7 @@ pub mod std_mod {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ActivePusRequestStd {
target_id: TargetId,
target_id: ComponentId,
token: VerificationToken<TcStateStarted>,
start_time: std::time::Instant,
timeout: Duration,
@ -1067,7 +1061,7 @@ pub mod std_mod {
impl ActivePusRequestStd {
pub fn new(
target_id: TargetId,
target_id: ComponentId,
token: VerificationToken<TcStateStarted>,
timeout: Duration,
) -> Self {
@ -1081,7 +1075,7 @@ pub mod std_mod {
}
impl ActiveRequestProvider for ActivePusRequestStd {
fn target_id(&self) -> TargetId {
fn target_id(&self) -> ComponentId {
self.target_id
}
fn token(&self) -> VerificationToken<TcStateStarted> {
@ -1102,37 +1096,52 @@ pub mod std_mod {
// will be no_std soon, see https://github.com/rust-lang/rust/issues/103765 .
#[derive(Debug, Clone, Error)]
pub enum GenericRoutingError {
#[error("not enough application data, expected at least {expected}, found {found}")]
NotEnoughAppData { expected: usize, found: usize },
#[error("Unknown target ID {0}")]
UnknownTargetId(TargetId),
#[error("Sending action request failed: {0}")]
SendError(GenericSendError),
pub enum PusTcFromMemError {
#[error("generic PUS error: {0}")]
EcssTmtc(#[from] EcssTmtcError),
#[error("invalid format of TC in memory: {0:?}")]
InvalidFormat(TcInMemory),
}
#[derive(Debug, Clone, Error)]
pub enum PusPacketHandlingError {
#[error("generic PUS error: {0}")]
Pus(#[from] PusError),
pub enum GenericRoutingError {
// #[error("not enough application data, expected at least {expected}, found {found}")]
// NotEnoughAppData { expected: usize, found: usize },
#[error("Unknown target ID {0}")]
UnknownTargetId(ComponentId),
#[error("Sending action request failed: {0}")]
Send(GenericSendError),
}
/// This error can be used for generic conversions from PUS Telecommands to request types.
///
/// Please note that this error can also be used if no request is generated and the PUS
/// service, subservice and application data is used directly to perform some request.
#[derive(Debug, Clone, Error)]
pub enum GenericConversionError {
#[error("wrong service number {0} for packet handler")]
WrongService(u8),
#[error("invalid subservice {0}")]
InvalidSubservice(u8),
#[error("not enough application data, expected at least {expected}, found {found}")]
NotEnoughAppData { expected: usize, found: usize },
#[error("PUS packet too large, does not fit in buffer: {0}")]
PusPacketTooLarge(usize),
#[error("invalid application data")]
InvalidAppData(String),
#[error("invalid format of TC in memory: {0:?}")]
InvalidTcInMemoryFormat(TcInMemory),
#[error("generic ECSS tmtc error: {0}")]
EcssTmtc(#[from] EcssTmtcError),
}
/// Wrapper type which tries to encapsulate all possible errors when handling PUS packets.
#[derive(Debug, Clone, Error)]
pub enum PusPacketHandlingError {
#[error("error polling PUS TC packet: {0}")]
TcPolling(#[from] EcssTmtcError),
#[error("error generating PUS reader from memory: {0}")]
TcFromMem(#[from] PusTcFromMemError),
#[error("generic request conversion error: {0}")]
RequestConversion(#[from] GenericConversionError),
#[error("request routing error: {0}")]
RequestRouting(#[from] GenericRoutingError),
#[error("invalid verification token")]
InvalidVerificationToken,
#[error("request routing error: {0}")]
RequestRoutingError(#[from] GenericRoutingError),
#[error("other error {0}")]
Other(String),
}
@ -1166,19 +1175,24 @@ pub mod std_mod {
}
pub trait EcssTcInMemConverter {
fn cache_ecss_tc_in_memory(
&mut self,
possible_packet: &TcInMemory,
) -> Result<(), PusPacketHandlingError>;
fn cache(&mut self, possible_packet: &TcInMemory) -> Result<(), PusTcFromMemError>;
fn tc_slice_raw(&self) -> &[u8];
fn convert_ecss_tc_in_memory_to_reader(
fn cache_and_convert(
&mut self,
possible_packet: &TcInMemory,
) -> Result<PusTcReader<'_>, PusPacketHandlingError> {
self.cache_ecss_tc_in_memory(possible_packet)?;
Ok(PusTcReader::new(self.tc_slice_raw())?.0)
) -> Result<PusTcReader<'_>, PusTcFromMemError> {
self.cache(possible_packet)?;
Ok(PusTcReader::new(self.tc_slice_raw())
.map_err(EcssTmtcError::Pus)?
.0)
}
fn convert(&self) -> Result<PusTcReader<'_>, PusTcFromMemError> {
Ok(PusTcReader::new(self.tc_slice_raw())
.map_err(EcssTmtcError::Pus)?
.0)
}
}
@ -1191,16 +1205,11 @@ pub mod std_mod {
}
impl EcssTcInMemConverter for EcssTcInVecConverter {
fn cache_ecss_tc_in_memory(
&mut self,
tc_in_memory: &TcInMemory,
) -> Result<(), PusPacketHandlingError> {
fn cache(&mut self, tc_in_memory: &TcInMemory) -> Result<(), PusTcFromMemError> {
self.pus_tc_raw = None;
match tc_in_memory {
super::TcInMemory::StoreAddr(_) => {
return Err(PusPacketHandlingError::InvalidTcInMemoryFormat(
tc_in_memory.clone(),
));
return Err(PusTcFromMemError::InvalidFormat(tc_in_memory.clone()));
}
super::TcInMemory::Vec(vec) => {
self.pus_tc_raw = Some(vec.clone());
@ -1234,16 +1243,20 @@ pub mod std_mod {
}
}
pub fn copy_tc_to_buf(&mut self, addr: StoreAddr) -> Result<(), PusPacketHandlingError> {
pub fn copy_tc_to_buf(&mut self, addr: StoreAddr) -> Result<(), PusTcFromMemError> {
// Keep locked section as short as possible.
let mut tc_pool = self.shared_tc_store.write().map_err(|_| {
PusPacketHandlingError::EcssTmtc(EcssTmtcError::Store(StoreError::LockError))
PusTcFromMemError::EcssTmtc(EcssTmtcError::Store(StoreError::LockError))
})?;
let tc_size = tc_pool
.len_of_data(&addr)
.map_err(|e| PusPacketHandlingError::EcssTmtc(EcssTmtcError::Store(e)))?;
let tc_size = tc_pool.len_of_data(&addr).map_err(EcssTmtcError::Store)?;
if tc_size > self.pus_buf.len() {
return Err(PusPacketHandlingError::PusPacketTooLarge(tc_size));
return Err(
EcssTmtcError::ByteConversion(ByteConversionError::ToSliceTooSmall {
found: self.pus_buf.len(),
expected: tc_size,
})
.into(),
);
}
let tc_guard = tc_pool.read_with_guard(addr);
// TODO: Proper error handling.
@ -1253,18 +1266,13 @@ pub mod std_mod {
}
impl EcssTcInMemConverter for EcssTcInSharedStoreConverter {
fn cache_ecss_tc_in_memory(
&mut self,
tc_in_memory: &TcInMemory,
) -> Result<(), PusPacketHandlingError> {
fn cache(&mut self, tc_in_memory: &TcInMemory) -> Result<(), PusTcFromMemError> {
match tc_in_memory {
super::TcInMemory::StoreAddr(addr) => {
self.copy_tc_to_buf(*addr)?;
}
super::TcInMemory::Vec(_) => {
return Err(PusPacketHandlingError::InvalidTcInMemoryFormat(
tc_in_memory.clone(),
));
return Err(PusTcFromMemError::InvalidFormat(tc_in_memory.clone()));
}
};
Ok(())
@ -1283,7 +1291,7 @@ pub mod std_mod {
pub tc_receiver: TcReceiver,
pub tm_sender: TmSender,
pub tm_apid: u16,
pub verification_handler: VerificationReporter,
pub verif_reporter: VerificationReporter,
}
/// This is a high-level PUS packet handler helper.
@ -1324,7 +1332,7 @@ pub mod std_mod {
tc_receiver,
tm_sender,
tm_apid,
verification_handler,
verif_reporter: verification_handler,
},
tc_in_mem_converter,
}
@ -1355,11 +1363,23 @@ pub mod std_mod {
}))
}
Err(e) => match e {
TryRecvTmtcError::Tmtc(e) => Err(PusPacketHandlingError::EcssTmtc(e)),
TryRecvTmtcError::Tmtc(e) => Err(PusPacketHandlingError::TcPolling(e)),
TryRecvTmtcError::Empty => Ok(None),
},
}
}
pub fn verif_reporter(&self) -> &VerificationReporter {
&self.common.verif_reporter
}
pub fn tc_in_mem_converter(&self) -> &TcInMemConverter {
&self.tc_in_mem_converter
}
pub fn tc_in_mem_converter_mut(&mut self) -> &mut TcInMemConverter {
&mut self.tc_in_mem_converter
}
}
pub type PusServiceHelperDynWithMpsc<TcInMemConverter, VerificationReporter> = PusServiceHelper<
@ -1423,7 +1443,7 @@ pub mod tests {
};
use crate::pus::verification::RequestId;
use crate::tmtc::tm_helper::SharedTmPool;
use crate::TargetId;
use crate::ComponentId;
use super::verification::std_mod::{
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender,
@ -1434,9 +1454,9 @@ pub mod tests {
VerificationReportingProvider, VerificationToken,
};
use super::{
EcssTcAndToken, EcssTcInSharedStoreConverter, EcssTcInVecConverter, GenericRoutingError,
MpscTcReceiver, PusPacketHandlerResult, PusPacketHandlingError, PusServiceHelper,
TcInMemory, TmAsVecSenderWithId, TmAsVecSenderWithMpsc,
EcssTcAndToken, EcssTcInSharedStoreConverter, EcssTcInVecConverter, GenericConversionError,
GenericRoutingError, MpscTcReceiver, PusPacketHandlerResult, PusPacketHandlingError,
PusServiceHelper, TcInMemory, TmAsVecSenderWithId, TmAsVecSenderWithMpsc,
TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithId,
};
@ -1732,7 +1752,9 @@ pub mod tests {
impl<const SERVICE: u8> TestConverter<SERVICE> {
pub fn check_service(&self, tc: &PusTcReader) -> Result<(), PusPacketHandlingError> {
if tc.service() != SERVICE {
return Err(PusPacketHandlingError::WrongService(tc.service()));
return Err(PusPacketHandlingError::RequestConversion(
GenericConversionError::WrongService(tc.service()),
));
}
Ok(())
}
@ -1751,8 +1773,8 @@ pub mod tests {
}
pub struct TestRouter<REQUEST> {
pub routing_requests: RefCell<VecDeque<(TargetId, REQUEST)>>,
pub routing_errors: RefCell<VecDeque<(TargetId, GenericRoutingError)>>,
pub routing_requests: RefCell<VecDeque<(ComponentId, REQUEST)>>,
pub routing_errors: RefCell<VecDeque<(ComponentId, GenericRoutingError)>>,
pub injected_routing_failure: RefCell<Option<GenericRoutingError>>,
}
@ -1776,7 +1798,7 @@ pub mod tests {
pub fn handle_error(
&self,
target_id: TargetId,
target_id: ComponentId,
_token: VerificationToken<TcStateAccepted>,
_tc: &PusTcReader,
error: GenericRoutingError,
@ -1792,7 +1814,7 @@ pub mod tests {
self.routing_errors.borrow().is_empty()
}
pub fn retrieve_next_routing_error(&mut self) -> (TargetId, GenericRoutingError) {
pub fn retrieve_next_routing_error(&mut self) -> (ComponentId, GenericRoutingError) {
if self.routing_errors.borrow().is_empty() {
panic!("no routing request available");
}
@ -1807,7 +1829,7 @@ pub mod tests {
self.routing_requests.borrow().is_empty()
}
pub fn retrieve_next_request(&mut self) -> (TargetId, REQUEST) {
pub fn retrieve_next_request(&mut self) -> (ComponentId, REQUEST) {
if self.routing_requests.borrow().is_empty() {
panic!("no routing request available");
}

View File

@ -83,10 +83,10 @@ impl<
return Ok(PusPacketHandlerResult::Empty);
}
let ecss_tc_and_token = possible_packet.unwrap();
let tc = self
.service_helper
.tc_in_mem_converter
.convert_ecss_tc_in_memory_to_reader(&ecss_tc_and_token.tc_in_memory)?;
self.service_helper
.tc_in_mem_converter_mut()
.cache(&ecss_tc_and_token.tc_in_memory)?;
let tc = self.service_helper.tc_in_mem_converter().convert()?;
let subservice = PusPacket::subservice(&tc);
let standard_subservice = scheduling::Subservice::try_from(subservice);
if standard_subservice.is_err() {
@ -100,16 +100,14 @@ impl<
scheduling::Subservice::TcEnableScheduling => {
let start_token = self
.service_helper
.common
.verification_handler
.verif_reporter()
.start_success(ecss_tc_and_token.token, time_stamp)
.expect("Error sending start success");
self.scheduler.enable();
if self.scheduler.is_enabled() {
self.service_helper
.common
.verification_handler
.verif_reporter()
.completion_success(start_token, time_stamp)
.expect("Error sending completion success");
} else {
@ -121,16 +119,14 @@ impl<
scheduling::Subservice::TcDisableScheduling => {
let start_token = self
.service_helper
.common
.verification_handler
.verif_reporter()
.start_success(ecss_tc_and_token.token, time_stamp)
.expect("Error sending start success");
self.scheduler.disable();
if !self.scheduler.is_enabled() {
self.service_helper
.common
.verification_handler
.verif_reporter()
.completion_success(start_token, time_stamp)
.expect("Error sending completion success");
} else {
@ -142,8 +138,7 @@ impl<
scheduling::Subservice::TcResetScheduling => {
let start_token = self
.service_helper
.common
.verification_handler
.verif_reporter()
.start_success(ecss_tc_and_token.token, time_stamp)
.expect("Error sending start success");
@ -152,8 +147,7 @@ impl<
.expect("Error resetting TC Pool");
self.service_helper
.common
.verification_handler
.verif_reporter()
.completion_success(start_token, time_stamp)
.expect("Error sending completion success");
}
@ -161,7 +155,7 @@ impl<
let start_token = self
.service_helper
.common
.verification_handler
.verif_reporter
.start_success(ecss_tc_and_token.token, time_stamp)
.expect("error sending start success");
@ -171,8 +165,7 @@ impl<
.expect("insertion of activity into pool failed");
self.service_helper
.common
.verification_handler
.verif_reporter()
.completion_success(start_token, time_stamp)
.expect("sending completion success failed");
}

View File

@ -12,8 +12,9 @@ use super::verification::{
};
use super::{
EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiverCore,
EcssTmSenderCore, MpscTcReceiver, PusServiceHelper, TmAsVecSenderWithBoundedMpsc,
TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithMpsc,
EcssTmSenderCore, GenericConversionError, MpscTcReceiver, PusServiceHelper,
TmAsVecSenderWithBoundedMpsc, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc,
TmInSharedPoolSenderWithMpsc,
};
/// This is a helper class for [std] environments to handle generic PUS 17 (test service) packets.
@ -55,19 +56,18 @@ impl<
return Ok(PusPacketHandlerResult::Empty);
}
let ecss_tc_and_token = possible_packet.unwrap();
let tc = self
.service_helper
.tc_in_mem_converter
.convert_ecss_tc_in_memory_to_reader(&ecss_tc_and_token.tc_in_memory)?;
self.service_helper
.tc_in_mem_converter_mut()
.cache(&ecss_tc_and_token.tc_in_memory)?;
let tc = self.service_helper.tc_in_mem_converter().convert()?;
if tc.service() != 17 {
return Err(PusPacketHandlingError::WrongService(tc.service()));
return Err(GenericConversionError::WrongService(tc.service()).into());
}
if tc.subservice() == 1 {
let mut partial_error = None;
let result = self
.service_helper
.common
.verification_handler
.verif_reporter()
.start_success(ecss_tc_and_token.token, time_stamp)
.map_err(|_| PartialPusHandlingError::Verification);
let start_token = if let Ok(result) = result {
@ -94,8 +94,7 @@ impl<
if let Some(start_token) = start_token {
if self
.service_helper
.common
.verification_handler
.verif_reporter()
.completion_success(start_token, time_stamp)
.is_err()
{
@ -162,8 +161,9 @@ mod tests {
use crate::pus::verification::RequestId;
use crate::pus::verification::{TcStateAccepted, VerificationToken};
use crate::pus::{
EcssTcInSharedStoreConverter, EcssTcInVecConverter, MpscTcReceiver, PusPacketHandlerResult,
PusPacketHandlingError, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc,
EcssTcInSharedStoreConverter, EcssTcInVecConverter, GenericConversionError, MpscTcReceiver,
PusPacketHandlerResult, PusPacketHandlingError, TmAsVecSenderWithMpsc,
TmInSharedPoolSenderWithBoundedMpsc,
};
use delegate::delegate;
use spacepackets::ecss::tc::{PusTcCreator, PusTcSecondaryHeader};
@ -320,7 +320,10 @@ mod tests {
let result = test_harness.handle_one_tc();
assert!(result.is_err());
let error = result.unwrap_err();
if let PusPacketHandlingError::WrongService(num) = error {
if let PusPacketHandlingError::RequestConversion(GenericConversionError::WrongService(
num,
)) = error
{
assert_eq!(num, 3);
} else {
panic!("unexpected error type {error}")

View File

@ -15,7 +15,7 @@ use spacepackets::{
ByteConversionError, CcsdsPacket,
};
use crate::{queue::GenericTargetedMessagingError, ChannelId, TargetId};
use crate::{queue::GenericTargetedMessagingError, ChannelId, ComponentId};
/// Generic request ID type. Requests can be associated with an ID to have a unique identifier
/// for them. This can be useful for tasks like tracking their progress.
@ -35,11 +35,11 @@ impl TargetAndApidId {
Self { apid, target }
}
pub fn raw(&self) -> TargetId {
pub fn raw(&self) -> ComponentId {
((self.apid as u64) << 32) | (self.target as u64)
}
pub fn full_target_id(&self) -> TargetId {
pub fn full_target_id(&self) -> ComponentId {
self.raw()
}

View File

@ -1,11 +1,13 @@
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::pus::action::ActionRequestWithId;
use satrs::request::RequestId;
use satrs::{
mode::{ModeAndSubmode, ModeReply, ModeRequest},
@ -46,11 +48,10 @@ struct TestDevice {
pub mode_node: ModeRequestHandlerMpscBounded,
pub mode_and_submode: ModeAndSubmode,
pub mode_requestor_info: Option<(RequestId, ChannelId)>,
pub action_queue: mpsc::Receiver<GenericMessage<ActionRequest>>,
}
pub struct ModeLeafDeviceHelper {
// pub
}
pub struct ModeLeafDeviceHelper {}
impl TestDevice {
pub fn run(&mut self) {