From 778512d50e29aadb279c9a8f5c2018a01c2a9a41 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 16 Oct 2025 12:53:06 +0200 Subject: [PATCH] rework event management module --- .github/workflows/ci.yml | 2 +- justfile | 6 +- satrs-example/src/config.rs | 2 +- satrs-example/src/events.rs | 10 +- satrs-example/src/pus/test.rs | 2 +- satrs/Cargo.toml | 9 +- satrs/src/event_man.rs | 629 +++++++++++---------- satrs/src/event_man_legacy.rs | 850 ++++++++++++++++++++++++++++ satrs/src/events.rs | 897 +++++------------------------- satrs/src/events_legacy.rs | 859 ++++++++++++++++++++++++++++ satrs/src/lib.rs | 4 +- satrs/src/pool.rs | 272 +++++---- satrs/src/pus/event.rs | 2 +- satrs/src/pus/event_man.rs | 8 +- satrs/src/pus/event_srv.rs | 6 +- satrs/tests/pus_autogen_events.rs | 94 ---- satrs/tests/pus_events.rs | 4 +- 17 files changed, 2395 insertions(+), 1261 deletions(-) create mode 100644 satrs/src/event_man_legacy.rs create mode 100644 satrs/src/events_legacy.rs delete mode 100644 satrs/tests/pus_autogen_events.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0aa189e..ab84b05 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,7 @@ jobs: steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly - - run: cargo +nightly doc --all-features --config 'build.rustdocflags=["--cfg", "docs_rs"]' + - run: RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc -p satrs --all-features clippy: name: Clippy diff --git a/justfile b/justfile index 197712e..ac898b6 100644 --- a/justfile +++ b/justfile @@ -17,5 +17,7 @@ fmt: clippy: cargo clippy -- -D warnings -docs: - cargo +nightly doc --all-features --config 'build.rustdocflags=["--cfg", "docs_rs"]' +docs-satrs: + RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p satrs --all-features + +docs: docs-satrs diff --git a/satrs-example/src/config.rs b/satrs-example/src/config.rs index 25ec32f..908bce1 100644 --- a/satrs-example/src/config.rs +++ b/satrs-example/src/config.rs @@ -11,7 +11,7 @@ use strum::IntoEnumIterator; use num_enum::{IntoPrimitive, TryFromPrimitive}; use satrs::{ - events::{EventU32TypedSev, SeverityInfo}, + events_legacy::{EventU32TypedSev, SeverityInfo}, pool::{StaticMemoryPool, StaticPoolConfig}, }; diff --git a/satrs-example/src/events.rs b/satrs-example/src/events.rs index 4be0613..bbe25c4 100644 --- a/satrs-example/src/events.rs +++ b/satrs-example/src/events.rs @@ -3,13 +3,13 @@ use std::sync::mpsc::{self}; use crate::pus::create_verification_reporter; use arbitrary_int::traits::Integer as _; use arbitrary_int::u11; -use satrs::event_man::{EventMessageU32, EventRoutingError}; +use satrs::event_man_legacy::{EventMessageU32, EventRoutingError}; use satrs::pus::event::EventTmHook; use satrs::pus::verification::VerificationReporter; use satrs::pus::EcssTmSender; use satrs::request::UniqueApidTargetId; use satrs::{ - event_man::{EventManagerWithBoundedMpsc, EventSendProvider, EventU32SenderMpscBounded}, + event_man_legacy::{EventManagerWithBoundedMpsc, EventSendProvider, EventU32SenderMpscBounded}, pus::{ event_man::{ DefaultPusEventU32TmCreator, EventReporter, EventRequest, EventRequestWithToken, @@ -219,7 +219,7 @@ impl EventHandler { #[cfg(test)] mod tests { use satrs::{ - events::EventU32, + events_legacy::EventU32, pus::verification::VerificationReporterConfig, spacepackets::ecss::{tm::PusTmReader, PusPacket}, tmtc::PacketAsVec, @@ -228,7 +228,7 @@ mod tests { use super::*; const TEST_CREATOR_ID: UniqueApidTargetId = UniqueApidTargetId::new(u11::new(1), 2); - const TEST_EVENT: EventU32 = EventU32::new(satrs::events::Severity::Info, 1, 1); + const TEST_EVENT: EventU32 = EventU32::new(satrs::events_legacy::Severity::Info, 1, 1); pub struct EventManagementTestbench { pub event_tx: mpsc::SyncSender, @@ -268,7 +268,7 @@ mod tests { .event_tx .send(EventMessageU32::new( TEST_CREATOR_ID.id(), - EventU32::new(satrs::events::Severity::Info, 1, 1), + EventU32::new(satrs::events_legacy::Severity::Info, 1, 1), )) .expect("failed to send event"); testbench.pus_event_handler.handle_event_requests(); diff --git a/satrs-example/src/pus/test.rs b/satrs-example/src/pus/test.rs index b7e5b5d..f79204c 100644 --- a/satrs-example/src/pus/test.rs +++ b/satrs-example/src/pus/test.rs @@ -1,7 +1,7 @@ use crate::pus::create_verification_reporter; use crate::tmtc::sender::TmTcSender; use log::info; -use satrs::event_man::{EventMessage, EventMessageU32}; +use satrs::event_man_legacy::{EventMessage, EventMessageU32}; use satrs::pus::test::PusService17TestHandler; use satrs::pus::verification::{FailParams, VerificationReporter, VerificationReportingProvider}; use satrs::pus::PartialPusHandlingError; diff --git a/satrs/Cargo.toml b/satrs/Cargo.toml index 28b64b1..c5f69b7 100644 --- a/satrs/Cargo.toml +++ b/satrs/Cargo.toml @@ -24,12 +24,13 @@ cobs = { version = "0.4", default-features = false } thiserror = { version = "2", default-features = false } hashbrown = { version = ">=0.14, <=0.15", optional = true } -static_cell = { version = "2", optional = true } -dyn-clone = { version = "1", optional = true } +static_cell = { version = "2" } heapless = { version = "0.9", optional = true } +dyn-clone = { version = "1", optional = true } downcast-rs = { version = "2", default-features = false, optional = true } bus = { version = "2.2", optional = true } crossbeam-channel = { version = "0.5", default-features = false, optional = true } +postcard = { version = "1", features = ["alloc"] } serde = { version = "1", default-features = false, optional = true } socket2 = { version = "0.6", features = ["all"], optional = true } arbitrary-int = "2" @@ -48,7 +49,7 @@ tempfile = "3" version = "1" [features] -default = ["std"] +default = ["std", "heapless"] std = [ "downcast-rs/std", "alloc", @@ -70,7 +71,7 @@ alloc = [ ] serde = ["dep:serde", "spacepackets/serde", "satrs-shared/serde"] crossbeam = ["crossbeam-channel"] -heapless = ["dep:heapless", "static_cell"] +# heapless = ["dep:heapless", "static_cell"] defmt = ["dep:defmt", "spacepackets/defmt"] test_util = [] diff --git a/satrs/src/event_man.rs b/satrs/src/event_man.rs index e430002..90de176 100644 --- a/satrs/src/event_man.rs +++ b/satrs/src/event_man.rs @@ -8,25 +8,25 @@ //! task is the [EventManager]. It receives all events and then routes them to event subscribers //! where appropriate. //! -//! The event manager has a listener table abstracted by the [ListenerMapProvider], which maps +//! The event manager has a listener table abstracted by the [ListenerMap], which maps //! listener groups identified by [ListenerKey]s to a [listener ID][ComponentId]. -//! It also contains a sender table abstracted by the [SenderMapProvider] which maps these sender -//! IDs to concrete [EventSendProvider]s. A simple approach would be to use one send event provider +//! It also contains a sender table abstracted by the [SenderMap] which maps these sender +//! IDs to concrete [EventSender]s. A simple approach would be to use one send event provider //! for each OBSW thread and then subscribe for all interesting events for a particular thread //! using the send event provider ID. //! //! This can be done with the [EventManager] like this: //! -//! 1. Provide a concrete [EventReceiveProvider] implementation. This abstraction allow to use different +//! 1. Provide a concrete [EventReceiver] implementation. This abstraction allow to use different //! message queue backends. A straightforward implementation where dynamic memory allocation is //! not a big concern would be to use the [std::sync::mpsc::Receiver] handle. The trait is //! already implemented for this type. //! 2. To set up event creators, create channel pairs using some message queue implementation. //! Each event creator gets a (cloned) sender component which allows it to send events to the //! manager. -//! 3. The event manager receives the receiver component as part of a [EventReceiveProvider] +//! 3. The event manager receives the receiver component as part of a [EventReceiver] //! implementation so all events are routed to the manager. -//! 4. Create the [event sender map][SenderMapProvider]s which allow routing events to +//! 4. Create the [event sender map][SenderMap]s which allow routing events to //! subscribers. You can now use the subscriber component IDs to subscribe //! for event groups, for example by using the [EventManager::subscribe_single] method. //! 5. Add the send provider as well using the [EventManager::add_sender] call so the event @@ -48,87 +48,60 @@ //! The [PUS event](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example/src/pus/event.rs) //! module and the generic [events module](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example/src/events.rs) //! show how the event management modules can be integrated into a more complex software. -use crate::events::{EventU16, EventU32, GenericEvent, LargestEventRaw, LargestGroupIdRaw}; -use crate::params::Params; -use crate::queue::GenericSendError; -use core::fmt::Debug; +use crate::{ + ComponentId, + events::{Event, EventId, GroupId}, + queue::GenericSendError, +}; use core::marker::PhantomData; use core::slice::Iter; -use crate::ComponentId; - #[cfg(feature = "alloc")] pub use alloc_mod::*; - #[cfg(feature = "std")] pub use std_mod::*; #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ListenerKey { - Single(LargestEventRaw), - Group(LargestGroupIdRaw), + Single(EventId), + Group(GroupId), All, } #[derive(Debug)] -pub struct EventMessage { +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct EventMessage { sender_id: ComponentId, - event: Event, - params: Option, + event: EventInstance, } -impl EventMessage { - pub fn new_generic(sender_id: ComponentId, event: Event, params: Option<&Parameters>) -> Self { - Self { - sender_id, - event, - params: params.cloned(), - } +impl EventMessage { + pub fn new(sender_id: ComponentId, event: EventInstance) -> Self { + EventMessage { sender_id, event } } pub fn sender_id(&self) -> ComponentId { self.sender_id } - pub fn event(&self) -> Event { - self.event - } - - pub fn params(&self) -> Option<&Parameters> { - self.params.as_ref() - } - - pub fn new(sender_id: ComponentId, event: Event) -> Self { - Self::new_generic(sender_id, event, None) - } - - pub fn new_with_params(sender_id: ComponentId, event: Event, params: &Parameters) -> Self { - Self::new_generic(sender_id, event, Some(params)) + pub fn event(&self) -> &EventInstance { + &self.event } } -pub type EventMessageU32 = EventMessage; -pub type EventMessageU16 = EventMessage; - -/// Generic abstraction -pub trait EventSendProvider { +/// Generic abstraction for event senders. +pub trait EventSender { type Error; fn target_id(&self) -> ComponentId; - fn send(&self, message: EventMessage) -> Result<(), Self::Error>; + fn send(&self, message: EventMessage) -> Result<(), Self::Error>; } -/// Generic abstraction for an event receiver. -pub trait EventReceiveProvider { - type Error; - - /// This function has to be provided by any event receiver. A call may or may not return - /// an event and optional auxiliary data. - fn try_recv_event(&self) -> Result>, Self::Error>; -} - -pub trait ListenerMapProvider { +pub trait ListenerMap { #[cfg(feature = "alloc")] fn get_listeners(&self) -> alloc::vec::Vec; fn contains_listener(&self, key: &ListenerKey) -> bool; @@ -137,52 +110,52 @@ pub trait ListenerMapProvider { fn remove_duplicates(&mut self, key: &ListenerKey); } -pub trait SenderMapProvider< - EventSender: EventSendProvider, - Event: GenericEvent = EventU32, - ParamProvider: Debug = Params, -> -{ +/// Generic abstraction for an event receiver. +pub trait EventReceiver { + type Error; + + /// This function has to be provided by any event receiver. A call may or may not return + /// an event. + fn try_recv_event(&self) -> Result>, Self::Error>; +} + +pub trait SenderMap, EventInstance: Event> { fn contains_send_event_provider(&self, target_id: &ComponentId) -> bool; - fn get_send_event_provider(&self, target_id: &ComponentId) -> Option<&EventSender>; - fn add_send_event_provider(&mut self, send_provider: EventSender) -> bool; + fn get_send_event_provider(&self, target_id: &ComponentId) -> Option<&EventSenderInstance>; + fn add_send_event_provider(&mut self, send_provider: EventSenderInstance) -> bool; } /// Generic event manager implementation. /// /// # Generics /// -/// * `EventReceiver`: [EventReceiveProvider] used to receive all events. -/// * `SenderMap`: [SenderMapProvider] which maps channel IDs to send providers. -/// * `ListenerMap`: [ListenerMapProvider] which maps listener keys to channel IDs. -/// * `EventSender`: [EventSendProvider] contained within the sender map which sends the events. -/// * `Event`: The event type. This type must implement the [GenericEvent]. Currently only [EventU32] -/// and [EventU16] are supported. -/// * `ParamProvider`: Auxiliary data which is sent with the event to provide optional context -/// information +/// * `EventReceiverInstance`: [EventReceiver] used to receive all events. +/// * `SenderMapInstance`: [SenderMap] which maps channel IDs to send providers. +/// * `ListenerMapInstance`: [ListenerMap] which maps listener keys to channel IDs. +/// * `EventSenderInstance`: [EventSender] contained within the sender map which sends the events. +/// * `Event`: The event type. This type must implement the [Event] trait. pub struct EventManager< - EventReceiver: EventReceiveProvider, - SenderMap: SenderMapProvider, - ListenerMap: ListenerMapProvider, - EventSender: EventSendProvider, - Event: GenericEvent = EventU32, - ParamProvider: Debug = Params, + EventReceiverInstance: EventReceiver, + SenderMapInstance: SenderMap, + ListenerMapInstance: ListenerMap, + EventSenderInstance: EventSender, + EventInstance: Event, > { - event_receiver: EventReceiver, - sender_map: SenderMap, - listener_map: ListenerMap, - phantom: core::marker::PhantomData<(EventSender, Event, ParamProvider)>, + event_receiver: EventReceiverInstance, + sender_map: SenderMapInstance, + listener_map: ListenerMapInstance, + phantom: core::marker::PhantomData<(EventSenderInstance, EventInstance)>, } #[derive(Debug)] -pub enum EventRoutingResult { +pub enum EventRoutingResult { /// No event was received Empty, /// An event was received and routed to listeners. Handled { num_recipients: u32, - event_msg: EventMessage, + event_msg: EventMessage, }, } @@ -194,25 +167,31 @@ pub enum EventRoutingError { } impl< - EventReceiver: EventReceiveProvider, - SenderMap: SenderMapProvider, - ListenerMap: ListenerMapProvider, - EventSender: EventSendProvider, - Event: GenericEvent + Copy, - ParamProvider: Debug, -> EventManager + EventReceiverInstance: EventReceiver, + SenderMapInstance: SenderMap, + ListenerMapInstance: ListenerMap, + EventSenderInstance: EventSender, + EventInstance: Event, +> + EventManager< + EventReceiverInstance, + SenderMapInstance, + ListenerMapInstance, + EventSenderInstance, + EventInstance, + > { pub fn remove_duplicates(&mut self, key: &ListenerKey) { self.listener_map.remove_duplicates(key) } /// Subscribe for a unique event. - pub fn subscribe_single(&mut self, event: &Event, sender_id: ComponentId) { - self.update_listeners(ListenerKey::Single(event.raw_as_largest_type()), sender_id); + pub fn subscribe_single(&mut self, event: EventId, sender_id: ComponentId) { + self.update_listeners(ListenerKey::Single(event), sender_id); } /// Subscribe for an event group. - pub fn subscribe_group(&mut self, group_id: LargestGroupIdRaw, sender_id: ComponentId) { + pub fn subscribe_group(&mut self, group_id: GroupId, sender_id: ComponentId) { self.update_listeners(ListenerKey::Group(group_id), sender_id); } @@ -225,18 +204,24 @@ impl< } } impl< - EventReceiver: EventReceiveProvider, - SenderMap: SenderMapProvider, - ListenerMap: ListenerMapProvider, - EventSenderMap: EventSendProvider, - Event: GenericEvent + Copy, - ParamProvider: Debug, -> EventManager + EventReceiverInstance: EventReceiver, + SenderMapInstance: SenderMap, + ListenerMapInstance: ListenerMap, + EventSenderInstance: EventSender, + EventInstance: Event, +> + EventManager< + EventReceiverInstance, + SenderMapInstance, + ListenerMapInstance, + EventSenderInstance, + EventInstance, + > { pub fn new_with_custom_maps( - event_receiver: EventReceiver, - sender_map: SenderMap, - listener_map: ListenerMap, + event_receiver: EventReceiverInstance, + sender_map: SenderMapInstance, + listener_map: ListenerMapInstance, ) -> Self { EventManager { listener_map, @@ -247,7 +232,7 @@ impl< } /// Add a new sender component which can be used to send events to subscribers. - pub fn add_sender(&mut self, send_provider: EventSenderMap) { + pub fn add_sender(&mut self, send_provider: EventSenderInstance) { if !self .sender_map .contains_send_event_provider(&send_provider.target_id()) @@ -263,13 +248,19 @@ impl< } impl< - EventReceiver: EventReceiveProvider, - SenderMap: SenderMapProvider, - ListenerMap: ListenerMapProvider, - EventSenderMap: EventSendProvider, - Event: GenericEvent + Copy, - ParamProvider: Clone + Debug, -> EventManager + EventReceiverInstance: EventReceiver, + SenderMapInstance: SenderMap, + ListenerMapInstance: ListenerMap, + EventSenderInstance: EventSender, + EventInstance: Event, +> + EventManager< + EventReceiverInstance, + SenderMapInstance, + ListenerMapInstance, + EventSenderInstance, + EventInstance, + > { /// This function will use the cached event receiver and try to receive one event. /// If an event was received, it will try to route that event to all subscribed event listeners. @@ -279,39 +270,37 @@ impl< /// If an error occurs during the routing, the error handler will be called. The error handler /// should take a reference to the event message as the first argument, and the routing error /// as the second argument. - pub fn try_event_handling, EventRoutingError)>( + pub fn try_event_handling, EventRoutingError)>( &self, mut error_handler: E, - ) -> EventRoutingResult { + ) -> EventRoutingResult { let mut num_recipients = 0; - let mut send_handler = - |key: &ListenerKey, event_msg: &EventMessage| { - if self.listener_map.contains_listener(key) { - if let Some(ids) = self.listener_map.get_listener_ids(key) { - for id in ids { - if let Some(sender) = self.sender_map.get_send_event_provider(id) { - if let Err(e) = sender.send(EventMessage::new_generic( - event_msg.sender_id, - event_msg.event, - event_msg.params.as_ref(), - )) { - error_handler(event_msg, EventRoutingError::Send(e)); - } else { - num_recipients += 1; - } + let mut send_handler = |key: &ListenerKey, event_msg: &EventMessage| { + if self.listener_map.contains_listener(key) { + if let Some(ids) = self.listener_map.get_listener_ids(key) { + for id in ids { + if let Some(sender) = self.sender_map.get_send_event_provider(id) { + if let Err(e) = sender.send(EventMessage::new( + event_msg.sender_id, + event_msg.event.clone(), + )) { + error_handler(event_msg, EventRoutingError::Send(e)); } else { - error_handler(event_msg, EventRoutingError::NoSenderForId(*id)); + num_recipients += 1; } + } else { + error_handler(event_msg, EventRoutingError::NoSenderForId(*id)); } - } else { - error_handler(event_msg, EventRoutingError::NoSendersForKey(*key)); } + } else { + error_handler(event_msg, EventRoutingError::NoSendersForKey(*key)); } - }; + } + }; if let Ok(Some(event_msg)) = self.event_receiver.try_recv_event() { - let single_key = ListenerKey::Single(event_msg.event.raw_as_largest_type()); + let single_key = ListenerKey::Single(event_msg.event().id()); send_handler(&single_key, &event_msg); - let group_key = ListenerKey::Group(event_msg.event.group_id_as_largest_type()); + let group_key = ListenerKey::Group(event_msg.event().id().group_id()); send_handler(&group_key, &event_msg); send_handler(&ListenerKey::All, &event_msg); return EventRoutingResult::Handled { @@ -328,46 +317,48 @@ pub mod alloc_mod { use alloc::vec::Vec; use hashbrown::HashMap; + use crate::events::EventErasedAlloc; + use super::*; /// Helper type which constrains the sender map and listener map generics to the [DefaultSenderMap] /// and the [DefaultListenerMap]. It uses regular mpsc channels as the message queue backend. - pub type EventManagerWithMpsc = EventManager< - EventU32ReceiverMpsc, - DefaultSenderMap, Event, ParamProvider>, + pub type EventManagerWithMpsc = EventManager< + EventDynParamReceiverMpsc, + DefaultSenderMap, EventInstance>, DefaultListenerMap, - EventSenderMpsc, + EventSenderMpsc, + EventInstance, >; /// Helper type which constrains the sender map and listener map generics to the [DefaultSenderMap] /// and the [DefaultListenerMap]. It uses /// [bounded mpsc senders](https://doc.rust-lang.org/std/sync/mpsc/struct.SyncSender.html) as the /// message queue backend. - pub type EventManagerWithBoundedMpsc = EventManager< - EventU32ReceiverMpsc, - DefaultSenderMap, Event, ParamProvider>, + pub type EventManagerWithBoundedMpsc = EventManager< + EventDynParamReceiverMpsc, + DefaultSenderMap, EventInstance>, DefaultListenerMap, - EventSenderMpscBounded, + EventSenderMpscBounded, + EventInstance, >; impl< - EventReceiver: EventReceiveProvider, - EventSender: EventSendProvider, - Event: GenericEvent + Copy, - ParamProvider: 'static + Debug, + EventReceiverInstance: EventReceiver, + EventSenderInstance: EventSender, + EventInstance: Event, > EventManager< - EventReceiver, - DefaultSenderMap, + EventReceiverInstance, + DefaultSenderMap, DefaultListenerMap, - EventSender, - Event, - ParamProvider, + EventSenderInstance, + EventInstance, > { /// Create an event manager where the sender table will be the [DefaultSenderMap] /// and the listener table will be the [DefaultListenerMap]. - pub fn new(event_receiver: EventReceiver) -> Self { + pub fn new(event_receiver: EventReceiverInstance) -> Self { Self { listener_map: DefaultListenerMap::default(), sender_map: DefaultSenderMap::default(), @@ -385,7 +376,7 @@ pub mod alloc_mod { listeners: HashMap>, } - impl ListenerMapProvider for DefaultListenerMap { + impl ListenerMap for DefaultListenerMap { fn get_listeners(&self) -> Vec { let mut key_list = Vec::new(); for key in self.listeners.keys() { @@ -424,19 +415,15 @@ pub mod alloc_mod { /// /// Simple implementation which uses a [HashMap] internally. pub struct DefaultSenderMap< - EventSender: EventSendProvider, - Event: GenericEvent = EventU32, - ParamProvider: Debug = Params, + EventSenderInstance: EventSender, + EventInstance: Event, > { - senders: HashMap, - phantom: PhantomData<(Event, ParamProvider)>, + senders: HashMap, + phantom: PhantomData, } - impl< - EventSender: EventSendProvider, - Event: GenericEvent, - ParamProvider: Debug, - > Default for DefaultSenderMap + impl, EventInstance: Event> Default + for DefaultSenderMap { fn default() -> Self { Self { @@ -446,24 +433,21 @@ pub mod alloc_mod { } } - impl< - EventSender: EventSendProvider, - Event: GenericEvent, - ParamProvider: Debug, - > SenderMapProvider - for DefaultSenderMap + impl, EventInstance: Event> + SenderMap + for DefaultSenderMap { fn contains_send_event_provider(&self, id: &ComponentId) -> bool { self.senders.contains_key(id) } - fn get_send_event_provider(&self, id: &ComponentId) -> Option<&EventSender> { + fn get_send_event_provider(&self, id: &ComponentId) -> Option<&EventSenderInstance> { self.senders .get(id) .filter(|sender| sender.target_id() == *id) } - fn add_send_event_provider(&mut self, send_provider: EventSender) -> bool { + fn add_send_event_provider(&mut self, send_provider: EventSenderInstance) -> bool { let id = send_provider.target_id(); if self.senders.contains_key(&id) { return false; @@ -475,20 +459,20 @@ pub mod alloc_mod { #[cfg(feature = "std")] pub mod std_mod { - use crate::queue::GenericReceiveError; + use crate::{ + events::{EventErasedAlloc, EventErasedHeapless}, + queue::GenericReceiveError, + }; use super::*; use std::sync::mpsc; - impl - EventReceiveProvider - for mpsc::Receiver> + impl EventReceiver + for mpsc::Receiver> { type Error = GenericReceiveError; - fn try_recv_event( - &self, - ) -> Result>, Self::Error> { + fn try_recv_event(&self) -> Result>, Self::Error> { match self.try_recv() { Ok(msg) => Ok(Some(msg)), Err(e) => match e { @@ -501,33 +485,35 @@ pub mod std_mod { } } - pub type EventU32ReceiverMpsc = - mpsc::Receiver>; - pub type EventU16ReceiverMpsc = - mpsc::Receiver>; + pub type EventDynParamReceiverMpsc = mpsc::Receiver>; + pub type EventHeaplessReceiverMpsc = + mpsc::Receiver>>; /// Generic event sender which uses a regular [mpsc::Sender] as the messaging backend to /// send events. #[derive(Clone)] - pub struct EventSenderMpsc { + pub struct EventSenderMpsc { target_id: ComponentId, - sender: mpsc::Sender>, + sender: mpsc::Sender>, } - impl EventSenderMpsc { - pub fn new(target_id: ComponentId, sender: mpsc::Sender>) -> Self { + impl EventSenderMpsc { + pub fn new( + target_id: ComponentId, + sender: mpsc::Sender>, + ) -> Self { Self { target_id, sender } } } - impl EventSendProvider for EventSenderMpsc { + impl EventSender for EventSenderMpsc { type Error = GenericSendError; fn target_id(&self) -> ComponentId { self.target_id } - fn send(&self, event_msg: EventMessage) -> Result<(), GenericSendError> { + fn send(&self, event_msg: EventMessage) -> Result<(), GenericSendError> { self.sender .send(event_msg) .map_err(|_| GenericSendError::RxDisconnected) @@ -537,16 +523,16 @@ pub mod std_mod { /// Generic event sender which uses the [mpsc::SyncSender] as the messaging backend to send /// events. This has the advantage that the channel is bounded and thus more deterministic. #[derive(Clone)] - pub struct EventSenderMpscBounded { + pub struct EventSenderMpscBounded { target_id: ComponentId, - sender: mpsc::SyncSender>, + sender: mpsc::SyncSender>, capacity: usize, } - impl EventSenderMpscBounded { + impl EventSenderMpscBounded { pub fn new( target_id: ComponentId, - sender: mpsc::SyncSender>, + sender: mpsc::SyncSender>, capacity: usize, ) -> Self { Self { @@ -557,14 +543,16 @@ pub mod std_mod { } } - impl EventSendProvider for EventSenderMpscBounded { + impl EventSender + for EventSenderMpscBounded + { type Error = GenericSendError; fn target_id(&self) -> ComponentId { self.target_id } - fn send(&self, event_msg: EventMessage) -> Result<(), Self::Error> { + fn send(&self, event_msg: EventMessage) -> Result<(), Self::Error> { if let Err(e) = self.sender.try_send(event_msg) { return match e { mpsc::TrySendError::Full(_) => { @@ -577,38 +565,58 @@ pub mod std_mod { } } - pub type EventU32SenderMpsc = EventSenderMpsc; - pub type EventU16SenderMpsc = EventSenderMpsc; - pub type EventU32SenderMpscBounded = EventSenderMpscBounded; - pub type EventU16SenderMpscBounded = EventSenderMpscBounded; + pub type EventDynParamSenderMpsc = EventSenderMpsc; + pub type EventHeaplessSenderMpsc = EventSenderMpsc>; + pub type EventDynParamSenderMpscBounded = EventSenderMpscBounded; + pub type EventHeaplessSenderMpscBounded = + EventSenderMpscBounded>; } #[cfg(test)] mod tests { - use super::*; - use crate::event_man::EventManager; - use crate::events::{EventU32, GenericEvent, Severity}; - use crate::params::{ParamsHeapless, ParamsRaw}; - use crate::pus::test_util::{TEST_COMPONENT_ID_0, TEST_COMPONENT_ID_1}; - use std::format; - use std::sync::mpsc::{self}; + use arbitrary_int::u14; - const TEST_EVENT: EventU32 = EventU32::new(Severity::Info, 0, 5); + use super::*; + use crate::events::{EventErasedAlloc, Severity}; + use crate::pus::test_util::{TEST_COMPONENT_ID_0, TEST_COMPONENT_ID_1}; + use std::sync::mpsc; + + const TEST_GROUP_ID_0: u14 = u14::new(0); + const TEST_GROUP_ID_1: u14 = u14::new(1); + + #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, serde::Serialize, serde::Deserialize)] + pub enum TestEvent { + Info, + Error, + InfoWithParams(u16), + OtherGroup, + } + + impl Event for TestEvent { + fn id(&self) -> EventId { + match self { + TestEvent::Info => EventId::new(Severity::Info, TEST_GROUP_ID_0, 0), + TestEvent::Error => EventId::new(Severity::High, TEST_GROUP_ID_0, 1), + TestEvent::InfoWithParams(_) => EventId::new(Severity::Info, TEST_GROUP_ID_0, 2), + TestEvent::OtherGroup => EventId::new(Severity::Info, TEST_GROUP_ID_1, 0), + } + } + } fn check_next_event( - expected: EventU32, - receiver: &mpsc::Receiver, - ) -> Option { + expected: TestEvent, + receiver: &mpsc::Receiver>, + ) { if let Ok(event_msg) = receiver.try_recv() { - assert_eq!(event_msg.event, expected); - return event_msg.params; + assert_eq!(event_msg.event.id(), expected.id()); + let event: TestEvent = postcard::from_bytes(event_msg.event().raw()).unwrap(); + assert_eq!(event, expected); } - None } fn check_handled_event( - res: EventRoutingResult, - expected: EventU32, + res: EventRoutingResult, + expected: &EventErasedAlloc, expected_num_sent: u32, expected_sender_id: ComponentId, ) { @@ -618,13 +626,16 @@ mod tests { event_msg, } = res { - assert_eq!(event_msg.event, expected); + assert_eq!(event_msg.event, *expected); assert_eq!(event_msg.sender_id, expected_sender_id); assert_eq!(num_recipients, expected_num_sent); } } - fn generic_event_man() -> (mpsc::Sender, EventManagerWithMpsc) { + fn generic_event_man() -> ( + mpsc::Sender>, + EventManagerWithMpsc, + ) { let (event_sender, event_receiver) = mpsc::channel(); (event_sender, EventManager::new(event_receiver)) } @@ -632,184 +643,209 @@ mod tests { #[test] fn test_basic() { let (event_sender, mut event_man) = generic_event_man(); - let event_grp_0 = EventU32::new(Severity::Info, 0, 0); - let event_grp_1_0 = EventU32::new(Severity::High, 1, 0); let (single_event_sender, single_event_receiver) = mpsc::channel(); let single_event_listener = EventSenderMpsc::new(0, single_event_sender); - event_man.subscribe_single(&event_grp_0, single_event_listener.target_id()); + event_man.subscribe_single(TestEvent::Info.id(), single_event_listener.target_id()); event_man.add_sender(single_event_listener); let (group_event_sender_0, group_event_receiver_0) = mpsc::channel(); - let group_event_listener = EventU32SenderMpsc::new(1, group_event_sender_0); - event_man.subscribe_group(event_grp_1_0.group_id(), group_event_listener.target_id()); + let group_event_listener = EventDynParamSenderMpsc::new(1, group_event_sender_0); + event_man.subscribe_group( + TestEvent::OtherGroup.id().group_id(), + group_event_listener.target_id(), + ); event_man.add_sender(group_event_listener); - let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| { + let error_handler = |event_msg: &EventMessage, e: EventRoutingError| { panic!("routing error occurred for event {:?}: {:?}", event_msg, e); }; + let event_grp_0 = EventErasedAlloc::new(&TestEvent::Info); + let event_grp_1 = EventErasedAlloc::new(&TestEvent::OtherGroup); // Test event with one listener event_sender - .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_grp_0)) + .send(EventMessage::new( + TEST_COMPONENT_ID_0.id(), + event_grp_0.clone(), + )) .expect("Sending single error failed"); let res = event_man.try_event_handling(&error_handler); - check_handled_event(res, event_grp_0, 1, TEST_COMPONENT_ID_0.id()); - check_next_event(event_grp_0, &single_event_receiver); + check_handled_event(res, &event_grp_0, 1, TEST_COMPONENT_ID_0.id()); + check_next_event(TestEvent::Info, &single_event_receiver); // Test event which is sent to all group listeners event_sender - .send(EventMessage::new(TEST_COMPONENT_ID_1.id(), event_grp_1_0)) + .send(EventMessage::new( + TEST_COMPONENT_ID_1.id(), + event_grp_1.clone(), + )) .expect("Sending group error failed"); let res = event_man.try_event_handling(&error_handler); - check_handled_event(res, event_grp_1_0, 1, TEST_COMPONENT_ID_1.id()); - check_next_event(event_grp_1_0, &group_event_receiver_0); + check_handled_event(res, &event_grp_1, 1, TEST_COMPONENT_ID_1.id()); + check_next_event(TestEvent::OtherGroup, &group_event_receiver_0); } #[test] fn test_with_basic_params() { - let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| { + let error_handler = |event_msg: &EventMessage, e: EventRoutingError| { panic!("routing error occurred for event {:?}: {:?}", event_msg, e); }; let (event_sender, mut event_man) = generic_event_man(); - let event_grp_0 = EventU32::new(Severity::Info, 0, 0); + let event_0 = TestEvent::InfoWithParams(5); let (single_event_sender, single_event_receiver) = mpsc::channel(); let single_event_listener = EventSenderMpsc::new(0, single_event_sender); - event_man.subscribe_single(&event_grp_0, single_event_listener.target_id()); + event_man.subscribe_single(event_0.id(), single_event_listener.target_id()); event_man.add_sender(single_event_listener); + let event_0_erased = EventErasedAlloc::new(&event_0); event_sender - .send(EventMessage::new_with_params( + .send(EventMessage::new( TEST_COMPONENT_ID_0.id(), - event_grp_0, - &Params::Heapless((2_u32, 3_u32).into()), + event_0_erased.clone(), )) .expect("Sending group error failed"); let res = event_man.try_event_handling(&error_handler); - check_handled_event(res, event_grp_0, 1, TEST_COMPONENT_ID_0.id()); - let aux = check_next_event(event_grp_0, &single_event_receiver); - assert!(aux.is_some()); - let aux = aux.unwrap(); - if let Params::Heapless(ParamsHeapless::Raw(ParamsRaw::U32Pair(pair))) = aux { - assert_eq!(pair.0, 2); - assert_eq!(pair.1, 3); - } else { - panic!("{}", format!("Unexpected auxiliary value type {:?}", aux)); - } + check_handled_event(res, &event_0_erased, 1, TEST_COMPONENT_ID_0.id()); + check_next_event(event_0, &single_event_receiver); } /// Test listening for multiple groups #[test] fn test_multi_group() { - let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| { + let error_handler = |event_msg: &EventMessage, e: EventRoutingError| { panic!("routing error occurred for event {:?}: {:?}", event_msg, e); }; let (event_sender, mut event_man) = generic_event_man(); let res = event_man.try_event_handling(error_handler); assert!(matches!(res, EventRoutingResult::Empty)); - let event_grp_0 = EventU32::new(Severity::Info, 0, 0); - let event_grp_1_0 = EventU32::new(Severity::High, 1, 0); + let event_grp_0 = TestEvent::Info; + let event_grp_1 = TestEvent::OtherGroup; let (event_grp_0_sender, event_grp_0_receiver) = mpsc::channel(); - let event_grp_0_and_1_listener = EventU32SenderMpsc::new(0, event_grp_0_sender); + let event_grp_0_and_1_listener = EventSenderMpsc::new(0, event_grp_0_sender); event_man.subscribe_group( - event_grp_0.group_id(), + event_grp_0.id().group_id(), event_grp_0_and_1_listener.target_id(), ); event_man.subscribe_group( - event_grp_1_0.group_id(), + event_grp_1.id().group_id(), event_grp_0_and_1_listener.target_id(), ); event_man.add_sender(event_grp_0_and_1_listener); + let event_grp_0_erased = EventErasedAlloc::new(&event_grp_0); + let event_grp_1_erased = EventErasedAlloc::new(&event_grp_1); event_sender - .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_grp_0)) + .send(EventMessage::new( + TEST_COMPONENT_ID_0.id(), + event_grp_0_erased.clone(), + )) .expect("Sending Event Group 0 failed"); event_sender - .send(EventMessage::new(TEST_COMPONENT_ID_1.id(), event_grp_1_0)) + .send(EventMessage::new( + TEST_COMPONENT_ID_1.id(), + event_grp_1_erased.clone(), + )) .expect("Sendign Event Group 1 failed"); let res = event_man.try_event_handling(error_handler); - check_handled_event(res, event_grp_0, 1, TEST_COMPONENT_ID_0.id()); + check_handled_event(res, &event_grp_0_erased, 1, TEST_COMPONENT_ID_0.id()); let res = event_man.try_event_handling(error_handler); - check_handled_event(res, event_grp_1_0, 1, TEST_COMPONENT_ID_1.id()); + check_handled_event(res, &event_grp_1_erased, 1, TEST_COMPONENT_ID_1.id()); check_next_event(event_grp_0, &event_grp_0_receiver); - check_next_event(event_grp_1_0, &event_grp_0_receiver); + check_next_event(event_grp_1, &event_grp_0_receiver); } /// Test listening to the same event from multiple listeners. Also test listening /// to both group and single events from one listener #[test] fn test_listening_to_same_event_and_multi_type() { - let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| { + let error_handler = |event_msg: &EventMessage, e: EventRoutingError| { panic!("routing error occurred for event {:?}: {:?}", event_msg, e); }; let (event_sender, mut event_man) = generic_event_man(); - let event_0 = EventU32::new(Severity::Info, 0, 5); - let event_1 = EventU32::new(Severity::High, 1, 0); + let event_0 = TestEvent::Info; + let event_1 = TestEvent::OtherGroup; + //let event_0 = EventU32::new(Severity::Info, 0, 5); + //let event_1 = EventU32::new(Severity::High, 1, 0); let (event_0_tx_0, event_0_rx_0) = mpsc::channel(); let (event_0_tx_1, event_0_rx_1) = mpsc::channel(); - let event_listener_0 = EventU32SenderMpsc::new(0, event_0_tx_0); - let event_listener_1 = EventU32SenderMpsc::new(1, event_0_tx_1); + let event_listener_0 = EventSenderMpsc::new(0, event_0_tx_0); + let event_listener_1 = EventSenderMpsc::new(1, event_0_tx_1); let event_listener_0_sender_id = event_listener_0.target_id(); - event_man.subscribe_single(&event_0, event_listener_0_sender_id); + event_man.subscribe_single(event_0.id(), event_listener_0_sender_id); event_man.add_sender(event_listener_0); let event_listener_1_sender_id = event_listener_1.target_id(); - event_man.subscribe_single(&event_0, event_listener_1_sender_id); + event_man.subscribe_single(event_0.id(), event_listener_1_sender_id); event_man.add_sender(event_listener_1); + let event_0_erased = EventErasedAlloc::new(&event_0); + let event_1_erased = EventErasedAlloc::new(&event_1); event_sender - .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_0)) + .send(EventMessage::new( + TEST_COMPONENT_ID_0.id(), + event_0_erased.clone(), + )) .expect("Triggering Event 0 failed"); let res = event_man.try_event_handling(error_handler); - check_handled_event(res, event_0, 2, TEST_COMPONENT_ID_0.id()); + check_handled_event(res, &event_0_erased, 2, TEST_COMPONENT_ID_0.id()); check_next_event(event_0, &event_0_rx_0); check_next_event(event_0, &event_0_rx_1); - event_man.subscribe_group(event_1.group_id(), event_listener_0_sender_id); + event_man.subscribe_group(event_1.id().group_id(), event_listener_0_sender_id); event_sender - .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_0)) + .send(EventMessage::new( + TEST_COMPONENT_ID_0.id(), + event_0_erased.clone(), + )) .expect("Triggering Event 0 failed"); event_sender - .send(EventMessage::new(TEST_COMPONENT_ID_1.id(), event_1)) + .send(EventMessage::new( + TEST_COMPONENT_ID_1.id(), + event_1_erased.clone(), + )) .expect("Triggering Event 1 failed"); // 3 Events messages will be sent now let res = event_man.try_event_handling(error_handler); - check_handled_event(res, event_0, 2, TEST_COMPONENT_ID_0.id()); + check_handled_event(res, &event_0_erased, 2, TEST_COMPONENT_ID_0.id()); let res = event_man.try_event_handling(error_handler); - check_handled_event(res, event_1, 1, TEST_COMPONENT_ID_1.id()); + check_handled_event(res, &event_1_erased, 1, TEST_COMPONENT_ID_1.id()); // Both the single event and the group event should arrive now check_next_event(event_0, &event_0_rx_0); check_next_event(event_1, &event_0_rx_0); // Do double insertion and then remove duplicates - event_man.subscribe_group(event_1.group_id(), event_listener_0_sender_id); - event_man.remove_duplicates(&ListenerKey::Group(event_1.group_id())); + event_man.subscribe_group(event_1.id().group_id(), event_listener_0_sender_id); + event_man.remove_duplicates(&ListenerKey::Group(event_1.id().group_id())); event_sender - .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_1)) + .send(EventMessage::new( + TEST_COMPONENT_ID_0.id(), + event_1_erased.clone(), + )) .expect("Triggering Event 1 failed"); let res = event_man.try_event_handling(error_handler); - check_handled_event(res, event_1, 1, TEST_COMPONENT_ID_0.id()); + check_handled_event(res, &event_1_erased, 1, TEST_COMPONENT_ID_0.id()); } #[test] fn test_all_events_listener() { - let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| { + let error_handler = |event_msg: &EventMessage, e: EventRoutingError| { panic!("routing error occurred for event {:?}: {:?}", event_msg, e); }; let (event_sender, event_receiver) = mpsc::channel(); let mut event_man = EventManagerWithMpsc::new(event_receiver); - let event_0 = EventU32::new(Severity::Info, 0, 5); - let event_1 = EventU32::new(Severity::High, 1, 0); + let event_0 = TestEvent::Info; + let event_1 = TestEvent::Error; let (event_0_tx_0, all_events_rx) = mpsc::channel(); - let all_events_listener = EventU32SenderMpsc::new(0, event_0_tx_0); + let all_events_listener = EventSenderMpsc::new(0, event_0_tx_0); event_man.subscribe_all(all_events_listener.target_id()); event_man.add_sender(all_events_listener); event_sender - .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_0)) + .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_0.into())) .expect("Triggering event 0 failed"); event_sender - .send(EventMessage::new(TEST_COMPONENT_ID_1.id(), event_1)) + .send(EventMessage::new(TEST_COMPONENT_ID_1.id(), event_1.into())) .expect("Triggering event 1 failed"); let res = event_man.try_event_handling(error_handler); - check_handled_event(res, event_0, 1, TEST_COMPONENT_ID_0.id()); + check_handled_event(res, &event_0.into(), 1, TEST_COMPONENT_ID_0.id()); let res = event_man.try_event_handling(error_handler); - check_handled_event(res, event_1, 1, TEST_COMPONENT_ID_1.id()); + check_handled_event(res, &event_1.into(), 1, TEST_COMPONENT_ID_1.id()); check_next_event(event_0, &all_events_rx); check_next_event(event_1, &all_events_rx); } @@ -817,17 +853,30 @@ mod tests { #[test] fn test_bounded_event_sender_queue_full() { let (event_sender, _event_receiver) = mpsc::sync_channel(3); - let event_sender = EventU32SenderMpscBounded::new(1, event_sender, 3); + let test_event = TestEvent::Info; + let event_sender = EventSenderMpscBounded::::new(1, event_sender, 3); event_sender - .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT)) + .send(EventMessage::new( + TEST_COMPONENT_ID_0.id(), + test_event.into(), + )) .expect("sending test event failed"); event_sender - .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT)) + .send(EventMessage::new( + TEST_COMPONENT_ID_0.id(), + test_event.into(), + )) .expect("sending test event failed"); event_sender - .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT)) + .send(EventMessage::new( + TEST_COMPONENT_ID_0.id(), + test_event.into(), + )) .expect("sending test event failed"); - let error = event_sender.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT)); + let error = event_sender.send(EventMessage::new( + TEST_COMPONENT_ID_0.id(), + test_event.into(), + )); if let Err(e) = error { assert!(matches!(e, GenericSendError::QueueFull(Some(3)))); } else { @@ -837,9 +886,13 @@ mod tests { #[test] fn test_bounded_event_sender_rx_dropped() { let (event_sender, event_receiver) = mpsc::sync_channel(3); - let event_sender = EventU32SenderMpscBounded::new(1, event_sender, 3); + let test_event = TestEvent::Info; + let event_sender = EventSenderMpscBounded::::new(1, event_sender, 3); drop(event_receiver); - if let Err(e) = event_sender.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT)) { + if let Err(e) = event_sender.send(EventMessage::new( + TEST_COMPONENT_ID_0.id(), + test_event.into(), + )) { assert!(matches!(e, GenericSendError::RxDisconnected)); } else { panic!("Expected error"); diff --git a/satrs/src/event_man_legacy.rs b/satrs/src/event_man_legacy.rs new file mode 100644 index 0000000..79c6c80 --- /dev/null +++ b/satrs/src/event_man_legacy.rs @@ -0,0 +1,850 @@ +//! # Event management and forwarding +//! +//! This is a legacy module. It is recommended to use [super::event_man] instead. +//! +//! It is recommended to read the +//! [sat-rs book chapter](https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/book/events.html) +//! about events first. +//! +//! This module provides components to perform event routing. The most important component for this +//! task is the [EventManager]. It receives all events and then routes them to event subscribers +//! where appropriate. +//! +//! The event manager has a listener table abstracted by the [ListenerMapProvider], which maps +//! listener groups identified by [ListenerKey]s to a [listener ID][ComponentId]. +//! It also contains a sender table abstracted by the [SenderMapProvider] which maps these sender +//! IDs to concrete [EventSendProvider]s. A simple approach would be to use one send event provider +//! for each OBSW thread and then subscribe for all interesting events for a particular thread +//! using the send event provider ID. +//! +//! This can be done with the [EventManager] like this: +//! +//! 1. Provide a concrete [EventReceiveProvider] implementation. This abstraction allow to use different +//! message queue backends. A straightforward implementation where dynamic memory allocation is +//! not a big concern would be to use the [std::sync::mpsc::Receiver] handle. The trait is +//! already implemented for this type. +//! 2. To set up event creators, create channel pairs using some message queue implementation. +//! Each event creator gets a (cloned) sender component which allows it to send events to the +//! manager. +//! 3. The event manager receives the receiver component as part of a [EventReceiveProvider] +//! implementation so all events are routed to the manager. +//! 4. Create the [event sender map][SenderMapProvider]s which allow routing events to +//! subscribers. You can now use the subscriber component IDs to subscribe +//! for event groups, for example by using the [EventManager::subscribe_single] method. +//! 5. Add the send provider as well using the [EventManager::add_sender] call so the event +//! manager can route listener groups to a the send provider. +//! +//! Some components like a PUS Event Service or PUS Event Action Service might require all +//! events to package them as telemetry or start actions where applicable. +//! Other components might only be interested in certain events. For example, a thermal system +//! handler might only be interested in temperature events generated by a thermal sensor component. +//! +//! # Examples +//! +//! You can check [integration test](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs/tests/pus_events.rs) +//! for a concrete example using multi-threading where events are routed to +//! different threads. +//! +//! The [satrs-example](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example) +//! also contains a full event manager instance and exposes a test event via the PUS test service. +//! The [PUS event](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example/src/pus/event.rs) +//! module and the generic [events module](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example/src/events.rs) +//! show how the event management modules can be integrated into a more complex software. +use crate::events_legacy::{EventU16, EventU32, GenericEvent, LargestEventRaw, LargestGroupIdRaw}; +use crate::params::Params; +use crate::queue::GenericSendError; +use core::fmt::Debug; +use core::marker::PhantomData; +use core::slice::Iter; + +use crate::ComponentId; + +#[cfg(feature = "alloc")] +pub use alloc_mod::*; + +#[cfg(feature = "std")] +pub use std_mod::*; + +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] +pub enum ListenerKey { + Single(LargestEventRaw), + Group(LargestGroupIdRaw), + All, +} + +#[derive(Debug)] +pub struct EventMessage { + sender_id: ComponentId, + event: Event, + params: Option, +} + +impl EventMessage { + pub fn new_generic(sender_id: ComponentId, event: Event, params: Option<&Parameters>) -> Self { + Self { + sender_id, + event, + params: params.cloned(), + } + } + + pub fn sender_id(&self) -> ComponentId { + self.sender_id + } + + pub fn event(&self) -> Event { + self.event + } + + pub fn params(&self) -> Option<&Parameters> { + self.params.as_ref() + } + + pub fn new(sender_id: ComponentId, event: Event) -> Self { + Self::new_generic(sender_id, event, None) + } + + pub fn new_with_params(sender_id: ComponentId, event: Event, params: &Parameters) -> Self { + Self::new_generic(sender_id, event, Some(params)) + } +} + +pub type EventMessageU32 = EventMessage; +pub type EventMessageU16 = EventMessage; + +/// Generic abstraction +pub trait EventSendProvider { + type Error; + + fn target_id(&self) -> ComponentId; + + fn send(&self, message: EventMessage) -> Result<(), Self::Error>; +} + +/// Generic abstraction for an event receiver. +pub trait EventReceiveProvider { + type Error; + + /// This function has to be provided by any event receiver. A call may or may not return + /// an event and optional auxiliary data. + fn try_recv_event(&self) -> Result>, Self::Error>; +} + +pub trait ListenerMapProvider { + #[cfg(feature = "alloc")] + fn get_listeners(&self) -> alloc::vec::Vec; + fn contains_listener(&self, key: &ListenerKey) -> bool; + fn get_listener_ids(&self, key: &ListenerKey) -> Option>; + fn add_listener(&mut self, key: ListenerKey, listener_id: ComponentId) -> bool; + fn remove_duplicates(&mut self, key: &ListenerKey); +} + +pub trait SenderMapProvider< + EventSender: EventSendProvider, + Event: GenericEvent = EventU32, + ParamProvider: Debug = Params, +> +{ + fn contains_send_event_provider(&self, target_id: &ComponentId) -> bool; + + fn get_send_event_provider(&self, target_id: &ComponentId) -> Option<&EventSender>; + fn add_send_event_provider(&mut self, send_provider: EventSender) -> bool; +} + +/// Generic event manager implementation. +/// +/// # Generics +/// +/// * `EventReceiver`: [EventReceiveProvider] used to receive all events. +/// * `SenderMap`: [SenderMapProvider] which maps channel IDs to send providers. +/// * `ListenerMap`: [ListenerMapProvider] which maps listener keys to channel IDs. +/// * `EventSender`: [EventSendProvider] contained within the sender map which sends the events. +/// * `Event`: The event type. This type must implement the [GenericEvent]. Currently only [EventU32] +/// and [EventU16] are supported. +/// * `ParamProvider`: Auxiliary data which is sent with the event to provide optional context +/// information +pub struct EventManager< + EventReceiver: EventReceiveProvider, + SenderMap: SenderMapProvider, + ListenerMap: ListenerMapProvider, + EventSender: EventSendProvider, + Event: GenericEvent = EventU32, + ParamProvider: Debug = Params, +> { + event_receiver: EventReceiver, + sender_map: SenderMap, + listener_map: ListenerMap, + phantom: core::marker::PhantomData<(EventSender, Event, ParamProvider)>, +} + +#[derive(Debug)] +pub enum EventRoutingResult { + /// No event was received + Empty, + /// An event was received and routed to listeners. + Handled { + num_recipients: u32, + event_msg: EventMessage, + }, +} + +#[derive(Debug)] +pub enum EventRoutingError { + Send(GenericSendError), + NoSendersForKey(ListenerKey), + NoSenderForId(ComponentId), +} + +impl< + EventReceiver: EventReceiveProvider, + SenderMap: SenderMapProvider, + ListenerMap: ListenerMapProvider, + EventSender: EventSendProvider, + Event: GenericEvent + Copy, + ParamProvider: Debug, +> EventManager +{ + pub fn remove_duplicates(&mut self, key: &ListenerKey) { + self.listener_map.remove_duplicates(key) + } + + /// Subscribe for a unique event. + pub fn subscribe_single(&mut self, event: &Event, sender_id: ComponentId) { + self.update_listeners(ListenerKey::Single(event.raw_as_largest_type()), sender_id); + } + + /// Subscribe for an event group. + pub fn subscribe_group(&mut self, group_id: LargestGroupIdRaw, sender_id: ComponentId) { + self.update_listeners(ListenerKey::Group(group_id), sender_id); + } + + /// Subscribe for all events received by the manager. + /// + /// For example, this can be useful for a handler component which sends every event as + /// a telemetry packet. + pub fn subscribe_all(&mut self, sender_id: ComponentId) { + self.update_listeners(ListenerKey::All, sender_id); + } +} +impl< + EventReceiver: EventReceiveProvider, + SenderMap: SenderMapProvider, + ListenerMap: ListenerMapProvider, + EventSenderMap: EventSendProvider, + Event: GenericEvent + Copy, + ParamProvider: Debug, +> EventManager +{ + pub fn new_with_custom_maps( + event_receiver: EventReceiver, + sender_map: SenderMap, + listener_map: ListenerMap, + ) -> Self { + EventManager { + listener_map, + sender_map, + event_receiver, + phantom: PhantomData, + } + } + + /// Add a new sender component which can be used to send events to subscribers. + pub fn add_sender(&mut self, send_provider: EventSenderMap) { + if !self + .sender_map + .contains_send_event_provider(&send_provider.target_id()) + { + self.sender_map.add_send_event_provider(send_provider); + } + } + + /// Generic function to update the event subscribers. + fn update_listeners(&mut self, key: ListenerKey, sender_id: ComponentId) { + self.listener_map.add_listener(key, sender_id); + } +} + +impl< + EventReceiver: EventReceiveProvider, + SenderMap: SenderMapProvider, + ListenerMap: ListenerMapProvider, + EventSenderMap: EventSendProvider, + Event: GenericEvent + Copy, + ParamProvider: Clone + Debug, +> EventManager +{ + /// This function will use the cached event receiver and try to receive one event. + /// If an event was received, it will try to route that event to all subscribed event listeners. + /// If this works without any issues, the [EventRoutingResult] will contain context information + /// about the routed event. + /// + /// If an error occurs during the routing, the error handler will be called. The error handler + /// should take a reference to the event message as the first argument, and the routing error + /// as the second argument. + pub fn try_event_handling, EventRoutingError)>( + &self, + mut error_handler: E, + ) -> EventRoutingResult { + let mut num_recipients = 0; + let mut send_handler = + |key: &ListenerKey, event_msg: &EventMessage| { + if self.listener_map.contains_listener(key) { + if let Some(ids) = self.listener_map.get_listener_ids(key) { + for id in ids { + if let Some(sender) = self.sender_map.get_send_event_provider(id) { + if let Err(e) = sender.send(EventMessage::new_generic( + event_msg.sender_id, + event_msg.event, + event_msg.params.as_ref(), + )) { + error_handler(event_msg, EventRoutingError::Send(e)); + } else { + num_recipients += 1; + } + } else { + error_handler(event_msg, EventRoutingError::NoSenderForId(*id)); + } + } + } else { + error_handler(event_msg, EventRoutingError::NoSendersForKey(*key)); + } + } + }; + if let Ok(Some(event_msg)) = self.event_receiver.try_recv_event() { + let single_key = ListenerKey::Single(event_msg.event.raw_as_largest_type()); + send_handler(&single_key, &event_msg); + let group_key = ListenerKey::Group(event_msg.event.group_id_as_largest_type()); + send_handler(&group_key, &event_msg); + send_handler(&ListenerKey::All, &event_msg); + return EventRoutingResult::Handled { + num_recipients, + event_msg, + }; + } + EventRoutingResult::Empty + } +} + +#[cfg(feature = "alloc")] +pub mod alloc_mod { + use alloc::vec::Vec; + use hashbrown::HashMap; + + use super::*; + + /// Helper type which constrains the sender map and listener map generics to the [DefaultSenderMap] + /// and the [DefaultListenerMap]. It uses regular mpsc channels as the message queue backend. + pub type EventManagerWithMpsc = EventManager< + EventU32ReceiverMpsc, + DefaultSenderMap, Event, ParamProvider>, + DefaultListenerMap, + EventSenderMpsc, + >; + + /// Helper type which constrains the sender map and listener map generics to the [DefaultSenderMap] + /// and the [DefaultListenerMap]. It uses + /// [bounded mpsc senders](https://doc.rust-lang.org/std/sync/mpsc/struct.SyncSender.html) as the + /// message queue backend. + pub type EventManagerWithBoundedMpsc = EventManager< + EventU32ReceiverMpsc, + DefaultSenderMap, Event, ParamProvider>, + DefaultListenerMap, + EventSenderMpscBounded, + >; + + impl< + EventReceiver: EventReceiveProvider, + EventSender: EventSendProvider, + Event: GenericEvent + Copy, + ParamProvider: 'static + Debug, + > + EventManager< + EventReceiver, + DefaultSenderMap, + DefaultListenerMap, + EventSender, + Event, + ParamProvider, + > + { + /// Create an event manager where the sender table will be the [DefaultSenderMap] + /// and the listener table will be the [DefaultListenerMap]. + pub fn new(event_receiver: EventReceiver) -> Self { + Self { + listener_map: DefaultListenerMap::default(), + sender_map: DefaultSenderMap::default(), + event_receiver, + phantom: PhantomData, + } + } + } + + /// Default listener map. + /// + /// Simple implementation which uses a [HashMap] and a [Vec] internally. + #[derive(Default)] + pub struct DefaultListenerMap { + listeners: HashMap>, + } + + impl ListenerMapProvider for DefaultListenerMap { + fn get_listeners(&self) -> Vec { + let mut key_list = Vec::new(); + for key in self.listeners.keys() { + key_list.push(*key); + } + key_list + } + + fn contains_listener(&self, key: &ListenerKey) -> bool { + self.listeners.contains_key(key) + } + + fn get_listener_ids(&self, key: &ListenerKey) -> Option> { + self.listeners.get(key).map(|vec| vec.iter()) + } + + fn add_listener(&mut self, key: ListenerKey, sender_id: ComponentId) -> bool { + if let Some(existing_list) = self.listeners.get_mut(&key) { + existing_list.push(sender_id); + } else { + let new_list = alloc::vec![sender_id]; + self.listeners.insert(key, new_list); + } + true + } + + fn remove_duplicates(&mut self, key: &ListenerKey) { + if let Some(list) = self.listeners.get_mut(key) { + list.sort_unstable(); + list.dedup(); + } + } + } + + /// Default sender map. + /// + /// Simple implementation which uses a [HashMap] internally. + pub struct DefaultSenderMap< + EventSender: EventSendProvider, + Event: GenericEvent = EventU32, + ParamProvider: Debug = Params, + > { + senders: HashMap, + phantom: PhantomData<(Event, ParamProvider)>, + } + + impl< + EventSender: EventSendProvider, + Event: GenericEvent, + ParamProvider: Debug, + > Default for DefaultSenderMap + { + fn default() -> Self { + Self { + senders: Default::default(), + phantom: Default::default(), + } + } + } + + impl< + EventSender: EventSendProvider, + Event: GenericEvent, + ParamProvider: Debug, + > SenderMapProvider + for DefaultSenderMap + { + fn contains_send_event_provider(&self, id: &ComponentId) -> bool { + self.senders.contains_key(id) + } + + fn get_send_event_provider(&self, id: &ComponentId) -> Option<&EventSender> { + self.senders + .get(id) + .filter(|sender| sender.target_id() == *id) + } + + fn add_send_event_provider(&mut self, send_provider: EventSender) -> bool { + let id = send_provider.target_id(); + if self.senders.contains_key(&id) { + return false; + } + self.senders.insert(id, send_provider).is_none() + } + } +} + +#[cfg(feature = "std")] +pub mod std_mod { + use crate::queue::GenericReceiveError; + + use super::*; + use std::sync::mpsc; + + impl + EventReceiveProvider + for mpsc::Receiver> + { + type Error = GenericReceiveError; + + fn try_recv_event( + &self, + ) -> Result>, Self::Error> { + match self.try_recv() { + Ok(msg) => Ok(Some(msg)), + Err(e) => match e { + mpsc::TryRecvError::Empty => Ok(None), + mpsc::TryRecvError::Disconnected => { + Err(GenericReceiveError::TxDisconnected(None)) + } + }, + } + } + } + + pub type EventU32ReceiverMpsc = + mpsc::Receiver>; + pub type EventU16ReceiverMpsc = + mpsc::Receiver>; + + /// Generic event sender which uses a regular [mpsc::Sender] as the messaging backend to + /// send events. + #[derive(Clone)] + pub struct EventSenderMpsc { + target_id: ComponentId, + sender: mpsc::Sender>, + } + + impl EventSenderMpsc { + pub fn new(target_id: ComponentId, sender: mpsc::Sender>) -> Self { + Self { target_id, sender } + } + } + + impl EventSendProvider for EventSenderMpsc { + type Error = GenericSendError; + + fn target_id(&self) -> ComponentId { + self.target_id + } + + fn send(&self, event_msg: EventMessage) -> Result<(), GenericSendError> { + self.sender + .send(event_msg) + .map_err(|_| GenericSendError::RxDisconnected) + } + } + + /// Generic event sender which uses the [mpsc::SyncSender] as the messaging backend to send + /// events. This has the advantage that the channel is bounded and thus more deterministic. + #[derive(Clone)] + pub struct EventSenderMpscBounded { + target_id: ComponentId, + sender: mpsc::SyncSender>, + capacity: usize, + } + + impl EventSenderMpscBounded { + pub fn new( + target_id: ComponentId, + sender: mpsc::SyncSender>, + capacity: usize, + ) -> Self { + Self { + target_id, + sender, + capacity, + } + } + } + + impl EventSendProvider for EventSenderMpscBounded { + type Error = GenericSendError; + + fn target_id(&self) -> ComponentId { + self.target_id + } + + fn send(&self, event_msg: EventMessage) -> Result<(), Self::Error> { + if let Err(e) = self.sender.try_send(event_msg) { + return match e { + mpsc::TrySendError::Full(_) => { + Err(GenericSendError::QueueFull(Some(self.capacity as u32))) + } + mpsc::TrySendError::Disconnected(_) => Err(GenericSendError::RxDisconnected), + }; + } + Ok(()) + } + } + + pub type EventU32SenderMpsc = EventSenderMpsc; + pub type EventU16SenderMpsc = EventSenderMpsc; + pub type EventU32SenderMpscBounded = EventSenderMpscBounded; + pub type EventU16SenderMpscBounded = EventSenderMpscBounded; +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::event_man_legacy::EventManager; + use crate::events_legacy::{EventU32, GenericEvent, Severity}; + use crate::params::{ParamsHeapless, ParamsRaw}; + use crate::pus::test_util::{TEST_COMPONENT_ID_0, TEST_COMPONENT_ID_1}; + use std::format; + use std::sync::mpsc::{self}; + + const TEST_EVENT: EventU32 = EventU32::new(Severity::Info, 0, 5); + + fn check_next_event( + expected: EventU32, + receiver: &mpsc::Receiver, + ) -> Option { + if let Ok(event_msg) = receiver.try_recv() { + assert_eq!(event_msg.event, expected); + return event_msg.params; + } + None + } + + fn check_handled_event( + res: EventRoutingResult, + expected: EventU32, + expected_num_sent: u32, + expected_sender_id: ComponentId, + ) { + assert!(matches!(res, EventRoutingResult::Handled { .. })); + if let EventRoutingResult::Handled { + num_recipients, + event_msg, + } = res + { + assert_eq!(event_msg.event, expected); + assert_eq!(event_msg.sender_id, expected_sender_id); + assert_eq!(num_recipients, expected_num_sent); + } + } + + fn generic_event_man() -> (mpsc::Sender, EventManagerWithMpsc) { + let (event_sender, event_receiver) = mpsc::channel(); + (event_sender, EventManager::new(event_receiver)) + } + + #[test] + fn test_basic() { + let (event_sender, mut event_man) = generic_event_man(); + let event_grp_0 = EventU32::new(Severity::Info, 0, 0); + let event_grp_1_0 = EventU32::new(Severity::High, 1, 0); + let (single_event_sender, single_event_receiver) = mpsc::channel(); + let single_event_listener = EventSenderMpsc::new(0, single_event_sender); + event_man.subscribe_single(&event_grp_0, single_event_listener.target_id()); + event_man.add_sender(single_event_listener); + let (group_event_sender_0, group_event_receiver_0) = mpsc::channel(); + let group_event_listener = EventU32SenderMpsc::new(1, group_event_sender_0); + event_man.subscribe_group(event_grp_1_0.group_id(), group_event_listener.target_id()); + event_man.add_sender(group_event_listener); + + let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| { + panic!("routing error occurred for event {:?}: {:?}", event_msg, e); + }; + // Test event with one listener + event_sender + .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_grp_0)) + .expect("Sending single error failed"); + let res = event_man.try_event_handling(&error_handler); + check_handled_event(res, event_grp_0, 1, TEST_COMPONENT_ID_0.id()); + check_next_event(event_grp_0, &single_event_receiver); + + // Test event which is sent to all group listeners + event_sender + .send(EventMessage::new(TEST_COMPONENT_ID_1.id(), event_grp_1_0)) + .expect("Sending group error failed"); + let res = event_man.try_event_handling(&error_handler); + check_handled_event(res, event_grp_1_0, 1, TEST_COMPONENT_ID_1.id()); + check_next_event(event_grp_1_0, &group_event_receiver_0); + } + + #[test] + fn test_with_basic_params() { + let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| { + panic!("routing error occurred for event {:?}: {:?}", event_msg, e); + }; + let (event_sender, mut event_man) = generic_event_man(); + let event_grp_0 = EventU32::new(Severity::Info, 0, 0); + let (single_event_sender, single_event_receiver) = mpsc::channel(); + let single_event_listener = EventSenderMpsc::new(0, single_event_sender); + event_man.subscribe_single(&event_grp_0, single_event_listener.target_id()); + event_man.add_sender(single_event_listener); + event_sender + .send(EventMessage::new_with_params( + TEST_COMPONENT_ID_0.id(), + event_grp_0, + &Params::Heapless((2_u32, 3_u32).into()), + )) + .expect("Sending group error failed"); + let res = event_man.try_event_handling(&error_handler); + check_handled_event(res, event_grp_0, 1, TEST_COMPONENT_ID_0.id()); + let aux = check_next_event(event_grp_0, &single_event_receiver); + assert!(aux.is_some()); + let aux = aux.unwrap(); + if let Params::Heapless(ParamsHeapless::Raw(ParamsRaw::U32Pair(pair))) = aux { + assert_eq!(pair.0, 2); + assert_eq!(pair.1, 3); + } else { + panic!("{}", format!("Unexpected auxiliary value type {:?}", aux)); + } + } + + /// Test listening for multiple groups + #[test] + fn test_multi_group() { + let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| { + panic!("routing error occurred for event {:?}: {:?}", event_msg, e); + }; + let (event_sender, mut event_man) = generic_event_man(); + let res = event_man.try_event_handling(error_handler); + assert!(matches!(res, EventRoutingResult::Empty)); + + let event_grp_0 = EventU32::new(Severity::Info, 0, 0); + let event_grp_1_0 = EventU32::new(Severity::High, 1, 0); + let (event_grp_0_sender, event_grp_0_receiver) = mpsc::channel(); + let event_grp_0_and_1_listener = EventU32SenderMpsc::new(0, event_grp_0_sender); + event_man.subscribe_group( + event_grp_0.group_id(), + event_grp_0_and_1_listener.target_id(), + ); + event_man.subscribe_group( + event_grp_1_0.group_id(), + event_grp_0_and_1_listener.target_id(), + ); + event_man.add_sender(event_grp_0_and_1_listener); + + event_sender + .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_grp_0)) + .expect("Sending Event Group 0 failed"); + event_sender + .send(EventMessage::new(TEST_COMPONENT_ID_1.id(), event_grp_1_0)) + .expect("Sendign Event Group 1 failed"); + let res = event_man.try_event_handling(error_handler); + check_handled_event(res, event_grp_0, 1, TEST_COMPONENT_ID_0.id()); + let res = event_man.try_event_handling(error_handler); + check_handled_event(res, event_grp_1_0, 1, TEST_COMPONENT_ID_1.id()); + + check_next_event(event_grp_0, &event_grp_0_receiver); + check_next_event(event_grp_1_0, &event_grp_0_receiver); + } + + /// Test listening to the same event from multiple listeners. Also test listening + /// to both group and single events from one listener + #[test] + fn test_listening_to_same_event_and_multi_type() { + let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| { + panic!("routing error occurred for event {:?}: {:?}", event_msg, e); + }; + let (event_sender, mut event_man) = generic_event_man(); + let event_0 = EventU32::new(Severity::Info, 0, 5); + let event_1 = EventU32::new(Severity::High, 1, 0); + let (event_0_tx_0, event_0_rx_0) = mpsc::channel(); + let (event_0_tx_1, event_0_rx_1) = mpsc::channel(); + let event_listener_0 = EventU32SenderMpsc::new(0, event_0_tx_0); + let event_listener_1 = EventU32SenderMpsc::new(1, event_0_tx_1); + let event_listener_0_sender_id = event_listener_0.target_id(); + event_man.subscribe_single(&event_0, event_listener_0_sender_id); + event_man.add_sender(event_listener_0); + let event_listener_1_sender_id = event_listener_1.target_id(); + event_man.subscribe_single(&event_0, event_listener_1_sender_id); + event_man.add_sender(event_listener_1); + event_sender + .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_0)) + .expect("Triggering Event 0 failed"); + let res = event_man.try_event_handling(error_handler); + check_handled_event(res, event_0, 2, TEST_COMPONENT_ID_0.id()); + check_next_event(event_0, &event_0_rx_0); + check_next_event(event_0, &event_0_rx_1); + event_man.subscribe_group(event_1.group_id(), event_listener_0_sender_id); + event_sender + .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_0)) + .expect("Triggering Event 0 failed"); + event_sender + .send(EventMessage::new(TEST_COMPONENT_ID_1.id(), event_1)) + .expect("Triggering Event 1 failed"); + + // 3 Events messages will be sent now + let res = event_man.try_event_handling(error_handler); + check_handled_event(res, event_0, 2, TEST_COMPONENT_ID_0.id()); + let res = event_man.try_event_handling(error_handler); + check_handled_event(res, event_1, 1, TEST_COMPONENT_ID_1.id()); + // Both the single event and the group event should arrive now + check_next_event(event_0, &event_0_rx_0); + check_next_event(event_1, &event_0_rx_0); + + // Do double insertion and then remove duplicates + event_man.subscribe_group(event_1.group_id(), event_listener_0_sender_id); + event_man.remove_duplicates(&ListenerKey::Group(event_1.group_id())); + event_sender + .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_1)) + .expect("Triggering Event 1 failed"); + let res = event_man.try_event_handling(error_handler); + check_handled_event(res, event_1, 1, TEST_COMPONENT_ID_0.id()); + } + + #[test] + fn test_all_events_listener() { + let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| { + panic!("routing error occurred for event {:?}: {:?}", event_msg, e); + }; + let (event_sender, event_receiver) = mpsc::channel(); + let mut event_man = EventManagerWithMpsc::new(event_receiver); + let event_0 = EventU32::new(Severity::Info, 0, 5); + let event_1 = EventU32::new(Severity::High, 1, 0); + let (event_0_tx_0, all_events_rx) = mpsc::channel(); + let all_events_listener = EventU32SenderMpsc::new(0, event_0_tx_0); + event_man.subscribe_all(all_events_listener.target_id()); + event_man.add_sender(all_events_listener); + event_sender + .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_0)) + .expect("Triggering event 0 failed"); + event_sender + .send(EventMessage::new(TEST_COMPONENT_ID_1.id(), event_1)) + .expect("Triggering event 1 failed"); + let res = event_man.try_event_handling(error_handler); + check_handled_event(res, event_0, 1, TEST_COMPONENT_ID_0.id()); + let res = event_man.try_event_handling(error_handler); + check_handled_event(res, event_1, 1, TEST_COMPONENT_ID_1.id()); + check_next_event(event_0, &all_events_rx); + check_next_event(event_1, &all_events_rx); + } + + #[test] + fn test_bounded_event_sender_queue_full() { + let (event_sender, _event_receiver) = mpsc::sync_channel(3); + let event_sender = EventU32SenderMpscBounded::new(1, event_sender, 3); + event_sender + .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT)) + .expect("sending test event failed"); + event_sender + .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT)) + .expect("sending test event failed"); + event_sender + .send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT)) + .expect("sending test event failed"); + let error = event_sender.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT)); + if let Err(e) = error { + assert!(matches!(e, GenericSendError::QueueFull(Some(3)))); + } else { + panic!("unexpected error {error:?}"); + } + } + #[test] + fn test_bounded_event_sender_rx_dropped() { + let (event_sender, event_receiver) = mpsc::sync_channel(3); + let event_sender = EventU32SenderMpscBounded::new(1, event_sender, 3); + drop(event_receiver); + if let Err(e) = event_sender.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT)) { + assert!(matches!(e, GenericSendError::RxDisconnected)); + } else { + panic!("Expected error"); + } + } +} diff --git a/satrs/src/events.rs b/satrs/src/events.rs index 1194087..9221ed1 100644 --- a/satrs/src/events.rs +++ b/satrs/src/events.rs @@ -1,8 +1,13 @@ -//! Event support module +//! # Event support module //! -//! This module includes the basic event structs [EventU32] and [EventU16] and versions with the -//! ECSS severity levels as a type parameter. These structs are simple abstractions on top of the -//! [u32] and [u16] types where the raw value is the unique identifier for a particular event. +//! The user can define events as custom structs or enumerations. +//! The event structures defined here are type erased and rely on some properties which +//! should be provided by the user through the [Event] and [serde::Serialize] trait. +//! +//! This in turn allows to use higher-level abstractions like the event manger. +//! +//! This module includes the basic type erased event structs [EventErasedAlloc] and +//! [EventErasedHeapless]. //! The abstraction also allows to group related events using a group ID, and the severity //! of an event is encoded inside the raw value itself with four possible [Severity] levels: //! @@ -10,42 +15,26 @@ //! - LOW //! - MEDIUM //! - HIGH -//! -//! All event structs implement the [EcssEnumeration] trait and can be created as constants. -//! This allows to easily create a static list of constant events which can then be used to generate -//! event telemetry using the PUS event manager modules. -//! -//! # Examples -//! -//! ``` -//! use satrs::events::{EventU16, EventU32, EventU32TypedSev, Severity, SeverityHigh, SeverityInfo}; -//! -//! const MSG_RECVD: EventU32TypedSev = EventU32TypedSev::new(1, 0); -//! const MSG_FAILED: EventU32 = EventU32::new(Severity::Low, 1, 1); -//! -//! const TEMPERATURE_HIGH: EventU32TypedSev = EventU32TypedSev::new(2, 0); -//! -//! let small_event = EventU16::new(Severity::Info, 3, 0); -//! ``` use core::fmt::Debug; use core::hash::Hash; -use core::marker::PhantomData; -use delegate::delegate; + +use arbitrary_int::{prelude::*, u14}; +#[cfg(feature = "heapless")] use spacepackets::ByteConversionError; -use spacepackets::ecss::EcssEnumeration; -use spacepackets::util::{ToBeBytes, UnsignedEnum}; /// Using a type definition allows to change this to u64 in the future more easily pub type LargestEventRaw = u32; /// Using a type definition allows to change this to u32 in the future more easily pub type LargestGroupIdRaw = u16; -pub const MAX_GROUP_ID_U32_EVENT: u16 = 2_u16.pow(14) - 1; -pub const MAX_GROUP_ID_U16_EVENT: u16 = 2_u16.pow(6) - 1; +pub const MAX_GROUP_ID_U32_EVENT: u16 = u14::MAX.value(); -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[derive( + Copy, Clone, PartialEq, Eq, Debug, Hash, num_enum::TryFromPrimitive, num_enum::IntoPrimitive, +)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] pub enum Severity { Info = 0, Low = 1, @@ -57,801 +46,203 @@ pub trait HasSeverity: Debug + PartialEq + Eq + Copy + Clone { const SEVERITY: Severity; } -/// Type level support struct -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub struct SeverityInfo {} -impl HasSeverity for SeverityInfo { - const SEVERITY: Severity = Severity::Info; +pub trait Event: Clone { + fn id(&self) -> EventId; } -/// Type level support struct -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub struct SeverityLow {} -impl HasSeverity for SeverityLow { - const SEVERITY: Severity = Severity::Low; -} +pub type GroupId = u14; -/// Type level support struct -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub struct SeverityMedium {} -impl HasSeverity for SeverityMedium { - const SEVERITY: Severity = Severity::Medium; -} - -/// Type level support struct -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub struct SeverityHigh {} -impl HasSeverity for SeverityHigh { - const SEVERITY: Severity = Severity::High; -} - -pub trait GenericEvent: EcssEnumeration + Copy + Clone { - type Raw; - type GroupId; - type UniqueId; - - fn raw(&self) -> Self::Raw; - fn severity(&self) -> Severity; - fn group_id(&self) -> Self::GroupId; - fn unique_id(&self) -> Self::UniqueId; - - fn raw_as_largest_type(&self) -> LargestEventRaw; - fn group_id_as_largest_type(&self) -> LargestGroupIdRaw; -} - -impl TryFrom for Severity { - type Error = (); - - fn try_from(value: u8) -> Result { - match value { - x if x == Severity::Info as u8 => Ok(Severity::Info), - x if x == Severity::Low as u8 => Ok(Severity::Low), - x if x == Severity::Medium as u8 => Ok(Severity::Medium), - x if x == Severity::High as u8 => Ok(Severity::High), - _ => Err(()), - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +/// Unique event identifier. +/// +/// Consists of a group ID, a unique ID and the severity. +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -struct EventBase { - severity: Severity, +pub struct EventId { group_id: GroupId, - unique_id: UniqueId, - phantom: PhantomData, + unique_id: u16, + severity: Severity, } -impl EventBase { - fn write_to_bytes( - &self, - raw: Raw, - buf: &mut [u8], - width: usize, - ) -> Result { - if buf.len() < width { - return Err(ByteConversionError::ToSliceTooSmall { - found: buf.len(), - expected: width, - }); +impl EventId { + pub fn new(severity: Severity, group_id: u14, unique_id: u16) -> Self { + Self { + severity, + group_id, + unique_id, } - buf.copy_from_slice(raw.to_be_bytes().as_ref()); - Ok(raw.written_len()) } -} -impl EventBase { - #[inline] - fn raw(&self) -> u32 { - ((self.severity as u32) << 30) | ((self.group_id as u32) << 16) | self.unique_id as u32 - } -} - -impl EventBase { - #[inline] - fn raw(&self) -> u16 { - ((self.severity as u16) << 14) | ((self.group_id as u16) << 8) | self.unique_id as u16 - } -} - -impl EventBase { - #[inline] - pub fn severity(&self) -> Severity { - self.severity - } -} - -impl EventBase { #[inline] pub fn unique_id(&self) -> u16 { self.unique_id } -} -impl EventBase { #[inline] - pub fn unique_id(&self) -> u8 { - self.unique_id + pub fn severity(&self) -> Severity { + self.severity } -} -impl EventBase { #[inline] - pub fn group_id(&self) -> u16 { + pub fn group_id(&self) -> u14 { self.group_id } -} -impl EventBase { - #[inline] - pub fn group_id(&self) -> u8 { - self.group_id + pub fn raw(&self) -> u32 { + ((self.severity as u32) << 30) + | ((self.group_id.as_u16() as u32) << 16) + | (self.unique_id as u32) } } -macro_rules! event_provider_impl { - () => { - #[inline] - fn raw(&self) -> Self::Raw { - self.base.raw() - } - - /// Retrieve the severity of an event. Returns None if that severity bit field of the raw event - /// ID is invalid - #[inline] - fn severity(&self) -> Severity { - self.base.severity() - } - - #[inline] - fn group_id(&self) -> Self::GroupId { - self.base.group_id() - } - - #[inline] - fn unique_id(&self) -> Self::UniqueId { - self.base.unique_id() - } - }; -} - -macro_rules! impl_event_provider { - ($BaseIdent: ident, $TypedIdent: ident, $raw: ty, $gid: ty, $uid: ty) => { - impl GenericEvent for $BaseIdent { - type Raw = $raw; - type GroupId = $gid; - type UniqueId = $uid; - - event_provider_impl!(); - - fn raw_as_largest_type(&self) -> LargestEventRaw { - self.raw().into() - } - - fn group_id_as_largest_type(&self) -> LargestGroupIdRaw { - self.group_id().into() - } - } - - impl GenericEvent for $TypedIdent { - type Raw = $raw; - type GroupId = $gid; - type UniqueId = $uid; - - delegate!(to self.event { - fn raw(&self) -> Self::Raw; - fn severity(&self) -> Severity; - fn group_id(&self) -> Self::GroupId; - fn unique_id(&self) -> Self::UniqueId; - fn raw_as_largest_type(&self) -> LargestEventRaw; - fn group_id_as_largest_type(&self) -> LargestGroupIdRaw; - }); - } - } -} - -macro_rules! try_from_impls { - ($SevIdent: ident, $severity: path, $raw: ty, $TypedSevIdent: ident) => { - impl TryFrom<$raw> for $TypedSevIdent<$SevIdent> { - type Error = Severity; - - fn try_from(raw: $raw) -> Result { - Self::try_from_generic($severity, raw) - } - } - }; -} - -macro_rules! const_from_fn { - ($from_fn_name: ident, $TypedIdent: ident, $SevIdent: ident) => { - pub const fn $from_fn_name(event: $TypedIdent<$SevIdent>) -> Self { - Self { - base: event.event.base, - } - } - }; -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct EventU32 { - base: EventBase, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct EventU32TypedSev { - event: EventU32, - phantom: PhantomData, -} - -impl From> for EventU32 { - fn from(e: EventU32TypedSev) -> Self { - Self { base: e.event.base } - } -} - -impl AsRef for EventU32TypedSev { - fn as_ref(&self) -> &EventU32 { - &self.event - } -} - -impl AsMut for EventU32TypedSev { - fn as_mut(&mut self) -> &mut EventU32 { - &mut self.event - } -} - -impl_event_provider!(EventU32, EventU32TypedSev, u32, u16, u16); - -impl EventU32 { - /// Generate an event. The raw representation of an event has 32 bits. - /// If the passed group ID is invalid (too large), None wil be returned - /// - /// # Parameter - /// - /// * `severity`: Each event has a [severity][Severity]. The raw value of the severity will - /// be stored inside the uppermost 2 bits of the raw event ID - /// * `group_id`: Related events can be grouped using a group ID. The group ID will occupy the - /// next 14 bits after the severity. Therefore, the size is limited by dec 16383 hex 0x3FFF. - /// * `unique_id`: Each event has a unique 16 bit ID occupying the last 16 bits of the - /// raw event ID - pub fn new_checked( - severity: Severity, - group_id: ::GroupId, - unique_id: ::UniqueId, - ) -> Option { - if group_id > MAX_GROUP_ID_U32_EVENT { - return None; - } - Some(Self { - base: EventBase { - severity, - group_id, - unique_id, - phantom: PhantomData, - }, - }) - } - - /// This constructor will panic if the passed group is is larger than [MAX_GROUP_ID_U32_EVENT]. - pub const fn new( - severity: Severity, - group_id: ::GroupId, - unique_id: ::UniqueId, - ) -> Self { - if group_id > MAX_GROUP_ID_U32_EVENT { - panic!("Group ID too large"); - } - Self { - base: EventBase { - severity, - group_id, - unique_id, - phantom: PhantomData, - }, - } - } - - pub fn from_be_bytes(bytes: [u8; 4]) -> Self { - Self::from(u32::from_be_bytes(bytes)) - } - - const_from_fn!(const_from_info, EventU32TypedSev, SeverityInfo); - const_from_fn!(const_from_low, EventU32TypedSev, SeverityLow); - const_from_fn!(const_from_medium, EventU32TypedSev, SeverityMedium); - const_from_fn!(const_from_high, EventU32TypedSev, SeverityHigh); -} - -impl From for EventU32 { +impl From for EventId { fn from(raw: u32) -> Self { // Severity conversion from u8 should never fail let severity = Severity::try_from(((raw >> 30) & 0b11) as u8).unwrap(); - let group_id = ((raw >> 16) & 0x3FFF) as u16; + let group_id = u14::new(((raw >> 16) & 0x3FFF) as u16); let unique_id = (raw & 0xFFFF) as u16; // Sanitized input, should never fail Self::new(severity, group_id, unique_id) } } -impl UnsignedEnum for EventU32 { - fn size(&self) -> usize { - core::mem::size_of::() +/// Event which was type erased and serialized into a [alloc::vec::Vec]. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg(feature = "alloc")] +pub struct EventErasedAlloc { + id: EventId, + event_raw: alloc::vec::Vec, +} + +#[cfg(feature = "alloc")] +impl EventErasedAlloc { + #[cfg(feature = "serde")] + /// Creates a new event by serializing the given event using [postcard]. + pub fn new(event: &(impl serde::Serialize + Event)) -> Self { + Self { + id: event.id(), + event_raw: postcard::to_allocvec(event).unwrap(), + } } - fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { - self.base.write_to_bytes(self.raw(), buf, self.size()) + pub fn new_with_raw_event(id: EventId, event_raw: &[u8]) -> Self { + Self { + id, + event_raw: event_raw.to_vec(), + } } - fn value(&self) -> u64 { - self.raw().into() + #[inline] + pub fn raw(&self) -> &[u8] { + &self.event_raw } } -impl EcssEnumeration for EventU32 { - fn pfc(&self) -> u8 { - u32::BITS as u8 +#[cfg(feature = "serde")] +#[cfg(feature = "alloc")] +impl From for EventErasedAlloc { + fn from(event: T) -> Self { + Self::new(&event) } } -impl EventU32TypedSev { - /// This is similar to [EventU32::new] but the severity is a type generic, which allows to - /// have distinct types for events with different severities - pub fn new_checked( - group_id: ::GroupId, - unique_id: ::UniqueId, - ) -> Option { - let event = EventU32::new_checked(SEVERITY::SEVERITY, group_id, unique_id)?; - Some(Self { - event, - phantom: PhantomData, +#[cfg(feature = "alloc")] +impl Event for EventErasedAlloc { + fn id(&self) -> EventId { + self.id + } +} + +/// Event which was type erased and serialized into a [heapless::vec::Vec]. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg(feature = "heapless")] +pub struct EventErasedHeapless { + id: EventId, + event_raw: heapless::vec::Vec, +} + +#[cfg(feature = "heapless")] +impl Event for EventErasedHeapless { + fn id(&self) -> EventId { + self.id + } +} + +#[cfg(feature = "heapless")] +impl EventErasedHeapless { + #[cfg(feature = "serde")] + /// Creates a new event by serializing the given event using [postcard]. + pub fn new(event: &(impl serde::Serialize + Event)) -> Result { + let ser_size = postcard::experimental::serialized_size(event).unwrap(); + if ser_size > N { + return Err(ByteConversionError::ToSliceTooSmall { + found: N, + expected: ser_size, + }); + } + let mut vec = heapless::Vec::::new(); + vec.resize(N, 0).unwrap(); + postcard::to_slice(event, vec.as_mut_slice()).unwrap(); + Ok(Self { + id: event.id(), + event_raw: vec, }) } - /// This constructor will panic if the `group_id` is larger than [MAX_GROUP_ID_U32_EVENT]. - pub const fn new( - group_id: ::GroupId, - unique_id: ::UniqueId, - ) -> Self { - let event = EventU32::new(SEVERITY::SEVERITY, group_id, unique_id); - Self { - event, - phantom: PhantomData, - } + pub fn new_with_raw_event(id: EventId, event_raw: heapless::Vec) -> Self { + Self { id, event_raw } } - fn try_from_generic(expected: Severity, raw: u32) -> Result { - let severity = Severity::try_from(((raw >> 30) & 0b11) as u8).unwrap(); - if severity != expected { - return Err(severity); - } - Ok(Self::new( - ((raw >> 16) & 0x3FFF) as u16, - (raw & 0xFFFF) as u16, - )) - } -} - -try_from_impls!(SeverityInfo, Severity::Info, u32, EventU32TypedSev); -try_from_impls!(SeverityLow, Severity::Low, u32, EventU32TypedSev); -try_from_impls!(SeverityMedium, Severity::Medium, u32, EventU32TypedSev); -try_from_impls!(SeverityHigh, Severity::High, u32, EventU32TypedSev); - -//noinspection RsTraitImplementation -impl UnsignedEnum for EventU32TypedSev { - delegate!(to self.event { - fn size(&self) -> usize; - fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result; - fn value(&self) -> u64; - }); -} - -//noinspection RsTraitImplementation -impl EcssEnumeration for EventU32TypedSev { - delegate!(to self.event { - fn pfc(&self) -> u8; - }); -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct EventU16 { - base: EventBase, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct EventU16TypedSev { - event: EventU16, - phantom: PhantomData, -} - -impl AsRef for EventU16TypedSev { - fn as_ref(&self) -> &EventU16 { - &self.event - } -} - -impl AsMut for EventU16TypedSev { - fn as_mut(&mut self) -> &mut EventU16 { - &mut self.event - } -} - -impl EventU16 { - /// Generate a small event. The raw representation of a small event has 16 bits. - /// If the passed group ID is invalid (too large), [None] wil be returned - /// - /// # Parameter - /// - /// * `severity`: Each event has a [severity][Severity]. The raw value of the severity will - /// be stored inside the uppermost 2 bits of the raw event ID - /// * `group_id`: Related events can be grouped using a group ID. The group ID will occupy the - /// next 6 bits after the severity. Therefore, the size is limited by dec 63 hex 0x3F. - /// * `unique_id`: Each event has a unique 8 bit ID occupying the last 8 bits of the - /// raw event ID - pub fn new_checked( - severity: Severity, - group_id: ::GroupId, - unique_id: ::UniqueId, - ) -> Option { - if group_id > (2u8.pow(6) - 1) { - return None; - } - Some(Self { - base: EventBase { - severity, - group_id, - unique_id, - phantom: Default::default(), - }, - }) - } - - /// This constructor will panic if the `group_id` is larger than [MAX_GROUP_ID_U16_EVENT]. - pub const fn new( - severity: Severity, - group_id: ::GroupId, - unique_id: ::UniqueId, - ) -> Self { - if group_id > (2u8.pow(6) - 1) { - panic!("Group ID too large"); - } - Self { - base: EventBase { - severity, - group_id, - unique_id, - phantom: PhantomData, - }, - } - } - pub fn from_be_bytes(bytes: [u8; 2]) -> Self { - Self::from(u16::from_be_bytes(bytes)) - } - - const_from_fn!(const_from_info, EventU16TypedSev, SeverityInfo); - const_from_fn!(const_from_low, EventU16TypedSev, SeverityLow); - const_from_fn!(const_from_medium, EventU16TypedSev, SeverityMedium); - const_from_fn!(const_from_high, EventU16TypedSev, SeverityHigh); -} - -impl From for EventU16 { - fn from(raw: ::Raw) -> Self { - let severity = Severity::try_from(((raw >> 14) & 0b11) as u8).unwrap(); - let group_id = ((raw >> 8) & 0x3F) as u8; - let unique_id = (raw & 0xFF) as u8; - // Sanitized input, new call should never fail - Self::new(severity, group_id, unique_id) - } -} - -impl UnsignedEnum for EventU16 { - fn size(&self) -> usize { - core::mem::size_of::() - } - - fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { - self.base.write_to_bytes(self.raw(), buf, self.size()) - } - - fn value(&self) -> u64 { - self.raw().into() - } -} -impl EcssEnumeration for EventU16 { #[inline] - fn pfc(&self) -> u8 { - u16::BITS as u8 - } -} - -impl EventU16TypedSev { - /// This is similar to [EventU16::new] but the severity is a type generic, which allows to - /// have distinct types for events with different severities - pub fn new_checked( - group_id: ::GroupId, - unique_id: ::UniqueId, - ) -> Option { - let event = EventU16::new_checked(SEVERITY::SEVERITY, group_id, unique_id)?; - Some(Self { - event, - phantom: PhantomData, - }) - } - - /// This constructor will panic if the `group_id` is larger than [MAX_GROUP_ID_U16_EVENT]. - pub const fn new( - group_id: ::GroupId, - unique_id: ::UniqueId, - ) -> Self { - let event = EventU16::new(SEVERITY::SEVERITY, group_id, unique_id); - Self { - event, - phantom: PhantomData, - } - } - - fn try_from_generic(expected: Severity, raw: u16) -> Result { - let severity = Severity::try_from(((raw >> 14) & 0b11) as u8).unwrap(); - if severity != expected { - return Err(severity); - } - Ok(Self::new(((raw >> 8) & 0x3F) as u8, (raw & 0xFF) as u8)) - } -} - -impl_event_provider!(EventU16, EventU16TypedSev, u16, u8, u8); - -//noinspection RsTraitImplementation -impl UnsignedEnum for EventU16TypedSev { - delegate!(to self.event { - fn size(&self) -> usize; - fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result; - fn value(&self) -> u64; - }); -} - -//noinspection RsTraitImplementation -impl EcssEnumeration for EventU16TypedSev { - delegate!(to self.event { - fn pfc(&self) -> u8; - }); -} - -try_from_impls!(SeverityInfo, Severity::Info, u16, EventU16TypedSev); -try_from_impls!(SeverityLow, Severity::Low, u16, EventU16TypedSev); -try_from_impls!(SeverityMedium, Severity::Medium, u16, EventU16TypedSev); -try_from_impls!(SeverityHigh, Severity::High, u16, EventU16TypedSev); - -impl PartialEq for EventU32TypedSev { - #[inline] - fn eq(&self, other: &EventU32) -> bool { - self.raw() == other.raw() - } -} - -impl PartialEq> for EventU32 { - #[inline] - fn eq(&self, other: &EventU32TypedSev) -> bool { - self.raw() == other.raw() - } -} - -impl PartialEq for EventU16TypedSev { - #[inline] - fn eq(&self, other: &EventU16) -> bool { - self.raw() == other.raw() - } -} - -impl PartialEq> for EventU16 { - #[inline] - fn eq(&self, other: &EventU16TypedSev) -> bool { - self.raw() == other.raw() + pub fn raw(&self) -> &[u8] { + &self.event_raw } } #[cfg(test)] mod tests { - use super::EventU32TypedSev; use super::*; - use spacepackets::ByteConversionError; - use std::mem::size_of; - fn assert_size(_: T, val: usize) { - assert_eq!(size_of::(), val); + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] + pub enum TestEvent { + Info, + ErrorOtherGroup, } - const INFO_EVENT: EventU32TypedSev = EventU32TypedSev::new(0, 0); - const INFO_EVENT_SMALL: EventU16TypedSev = EventU16TypedSev::new(0, 0); - const HIGH_SEV_EVENT: EventU32TypedSev = EventU32TypedSev::new(0x3FFF, 0xFFFF); - const HIGH_SEV_EVENT_SMALL: EventU16TypedSev = EventU16TypedSev::new(0x3F, 0xff); - - /// This working is a test in itself. - const INFO_REDUCED: EventU32 = EventU32::const_from_info(INFO_EVENT); - - #[test] - fn test_normal_from_raw_conversion() { - let conv_from_raw = EventU32TypedSev::::try_from(INFO_EVENT.raw()) - .expect("Creating typed EventU32 failed"); - assert_eq!(conv_from_raw, INFO_EVENT); - } - - #[test] - fn test_small_from_raw_conversion() { - let conv_from_raw = EventU16TypedSev::::try_from(INFO_EVENT_SMALL.raw()) - .expect("Creating typed EventU16 failed"); - assert_eq!(conv_from_raw, INFO_EVENT_SMALL); - } - - #[test] - fn verify_normal_size() { - assert_size(INFO_EVENT.raw(), 4) - } - - #[test] - fn verify_small_size() { - assert_size(INFO_EVENT_SMALL.raw(), 2) + impl Event for TestEvent { + fn id(&self) -> EventId { + match self { + TestEvent::Info => EventId::new(Severity::Info, u14::new(0), 0), + TestEvent::ErrorOtherGroup => EventId::new(Severity::High, u14::new(1), 1), + } + } } #[test] fn test_normal_event_getters() { - assert_eq!(INFO_EVENT.severity(), Severity::Info); - assert_eq!(INFO_EVENT.unique_id(), 0); - assert_eq!(INFO_EVENT.group_id(), 0); - let raw_event = INFO_EVENT.raw(); + assert_eq!(TestEvent::Info.id().severity(), Severity::Info); + assert_eq!(TestEvent::Info.id().unique_id(), 0); + assert_eq!(TestEvent::Info.id().group_id().value(), 0); + assert_eq!(TestEvent::ErrorOtherGroup.id().group_id().value(), 1); + assert_eq!(TestEvent::ErrorOtherGroup.id().unique_id(), 1); + let raw_event = TestEvent::Info.id().raw(); assert_eq!(raw_event, 0x00000000); } #[test] - fn test_small_event_getters() { - assert_eq!(INFO_EVENT_SMALL.severity(), Severity::Info); - assert_eq!(INFO_EVENT_SMALL.unique_id(), 0); - assert_eq!(INFO_EVENT_SMALL.group_id(), 0); - let raw_event = INFO_EVENT_SMALL.raw(); - assert_eq!(raw_event, 0x00000000); + #[cfg(feature = "serde")] + fn test_basic_erased_alloc_event() { + let event = EventErasedAlloc::new(&TestEvent::Info); + let test_event: TestEvent = postcard::from_bytes(event.raw()).unwrap(); + assert_eq!(test_event, TestEvent::Info); } #[test] - fn all_ones_event_regular() { - assert_eq!(HIGH_SEV_EVENT.severity(), Severity::High); - assert_eq!(HIGH_SEV_EVENT.group_id(), 0x3FFF); - assert_eq!(HIGH_SEV_EVENT.unique_id(), 0xFFFF); - let raw_event = HIGH_SEV_EVENT.raw(); - assert_eq!(raw_event, 0xFFFFFFFF); - } - - #[test] - fn all_ones_event_small() { - assert_eq!(HIGH_SEV_EVENT_SMALL.severity(), Severity::High); - assert_eq!(HIGH_SEV_EVENT_SMALL.group_id(), 0x3F); - assert_eq!(HIGH_SEV_EVENT_SMALL.unique_id(), 0xFF); - let raw_event = HIGH_SEV_EVENT_SMALL.raw(); - assert_eq!(raw_event, 0xFFFF); - } - - #[test] - fn invalid_group_id_normal() { - assert!(EventU32TypedSev::::new_checked(2_u16.pow(14), 0).is_none()); - } - - #[test] - fn invalid_group_id_small() { - assert!(EventU16TypedSev::::new_checked(2_u8.pow(6), 0).is_none()); - } - - #[test] - fn regular_new() { - assert_eq!( - EventU32TypedSev::::new_checked(0, 0) - .expect("Creating regular event failed"), - INFO_EVENT - ); - } - - #[test] - fn small_new() { - assert_eq!( - EventU16TypedSev::::new_checked(0, 0) - .expect("Creating regular event failed"), - INFO_EVENT_SMALL - ); - } - - #[test] - fn as_largest_type() { - let event_raw = HIGH_SEV_EVENT.raw_as_largest_type(); - assert_size(event_raw, 4); - assert_eq!(event_raw, 0xFFFFFFFF); - } - - #[test] - fn as_largest_type_for_small_event() { - let event_raw = HIGH_SEV_EVENT_SMALL.raw_as_largest_type(); - assert_size(event_raw, 4); - assert_eq!(event_raw, 0xFFFF); - } - - #[test] - fn as_largest_group_id() { - let group_id = HIGH_SEV_EVENT.group_id_as_largest_type(); - assert_size(group_id, 2); - assert_eq!(group_id, 0x3FFF); - } - - #[test] - fn as_largest_group_id_small_event() { - let group_id = HIGH_SEV_EVENT_SMALL.group_id_as_largest_type(); - assert_size(group_id, 2); - assert_eq!(group_id, 0x3F); - } - - #[test] - fn write_to_buf() { - let mut buf: [u8; 4] = [0; 4]; - assert!(HIGH_SEV_EVENT.write_to_be_bytes(&mut buf).is_ok()); - let val_from_raw = u32::from_be_bytes(buf); - assert_eq!(val_from_raw, 0xFFFFFFFF); - let event_read_back = EventU32::from_be_bytes(buf); - assert_eq!(event_read_back, HIGH_SEV_EVENT); - } - - #[test] - fn write_to_buf_small() { - let mut buf: [u8; 2] = [0; 2]; - assert!(HIGH_SEV_EVENT_SMALL.write_to_be_bytes(&mut buf).is_ok()); - let val_from_raw = u16::from_be_bytes(buf); - assert_eq!(val_from_raw, 0xFFFF); - let event_read_back = EventU16::from_be_bytes(buf); - assert_eq!(event_read_back, HIGH_SEV_EVENT_SMALL); - } - - #[test] - fn write_to_buf_insufficient_buf() { - let mut buf: [u8; 3] = [0; 3]; - let err = HIGH_SEV_EVENT.write_to_be_bytes(&mut buf); - assert!(err.is_err()); - let err = err.unwrap_err(); - if let ByteConversionError::ToSliceTooSmall { found, expected } = err { - assert_eq!(expected, 4); - assert_eq!(found, 3); - } - } - - #[test] - fn write_to_buf_small_insufficient_buf() { - let mut buf: [u8; 1] = [0; 1]; - let err = HIGH_SEV_EVENT_SMALL.write_to_be_bytes(&mut buf); - assert!(err.is_err()); - let err = err.unwrap_err(); - if let ByteConversionError::ToSliceTooSmall { found, expected } = err { - assert_eq!(expected, 2); - assert_eq!(found, 1); - } - } - - #[test] - fn severity_from_invalid_raw_val() { - let invalid = 0xFF; - assert!(Severity::try_from(invalid).is_err()); - let invalid = Severity::High as u8 + 1; - assert!(Severity::try_from(invalid).is_err()); - } - - #[test] - fn reduction() { - let event = EventU32TypedSev::::new(1, 1); - let raw = event.raw(); - let reduced: EventU32 = event.into(); - assert_eq!(reduced.group_id(), 1); - assert_eq!(reduced.unique_id(), 1); - assert_eq!(raw, reduced.raw()); - } - - #[test] - fn const_reducation() { - assert_eq!(INFO_REDUCED.raw(), INFO_EVENT.raw()); + #[cfg(all(feature = "serde", feature = "alloc"))] + fn test_basic_erased_heapless_event() { + let event = EventErasedHeapless::<8>::new(&TestEvent::Info).unwrap(); + let test_event: TestEvent = postcard::from_bytes(event.raw()).unwrap(); + assert_eq!(test_event, TestEvent::Info); } } diff --git a/satrs/src/events_legacy.rs b/satrs/src/events_legacy.rs new file mode 100644 index 0000000..016b34a --- /dev/null +++ b/satrs/src/events_legacy.rs @@ -0,0 +1,859 @@ +//! # Event support module +//! +//! This is a legacy module. It is recommended to use [super::events] instead. +//! +//! This module includes the basic event structs [EventU32] and [EventU16] and versions with the +//! ECSS severity levels as a type parameter. These structs are simple abstractions on top of the +//! [u32] and [u16] types where the raw value is the unique identifier for a particular event. +//! The abstraction also allows to group related events using a group ID, and the severity +//! of an event is encoded inside the raw value itself with four possible [Severity] levels: +//! +//! - INFO +//! - LOW +//! - MEDIUM +//! - HIGH +//! +//! All event structs implement the [EcssEnumeration] trait and can be created as constants. +//! This allows to easily create a static list of constant events which can then be used to generate +//! event telemetry using the PUS event manager modules. +//! +//! # Examples +//! +//! ``` +//! use satrs::events_legacy::{EventU16, EventU32, EventU32TypedSev, Severity, SeverityHigh, SeverityInfo}; +//! +//! const MSG_RECVD: EventU32TypedSev = EventU32TypedSev::new(1, 0); +//! const MSG_FAILED: EventU32 = EventU32::new(Severity::Low, 1, 1); +//! +//! const TEMPERATURE_HIGH: EventU32TypedSev = EventU32TypedSev::new(2, 0); +//! +//! let small_event = EventU16::new(Severity::Info, 3, 0); +//! ``` +use core::fmt::Debug; +use core::hash::Hash; +use core::marker::PhantomData; +use delegate::delegate; +use spacepackets::ByteConversionError; +use spacepackets::ecss::EcssEnumeration; +use spacepackets::util::{ToBeBytes, UnsignedEnum}; + +/// Using a type definition allows to change this to u64 in the future more easily +pub type LargestEventRaw = u32; +/// Using a type definition allows to change this to u32 in the future more easily +pub type LargestGroupIdRaw = u16; + +pub const MAX_GROUP_ID_U32_EVENT: u16 = 2_u16.pow(14) - 1; +pub const MAX_GROUP_ID_U16_EVENT: u16 = 2_u16.pow(6) - 1; + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Severity { + Info = 0, + Low = 1, + Medium = 2, + High = 3, +} + +pub trait HasSeverity: Debug + PartialEq + Eq + Copy + Clone { + const SEVERITY: Severity; +} + +/// Type level support struct +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub struct SeverityInfo {} +impl HasSeverity for SeverityInfo { + const SEVERITY: Severity = Severity::Info; +} + +/// Type level support struct +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub struct SeverityLow {} +impl HasSeverity for SeverityLow { + const SEVERITY: Severity = Severity::Low; +} + +/// Type level support struct +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub struct SeverityMedium {} +impl HasSeverity for SeverityMedium { + const SEVERITY: Severity = Severity::Medium; +} + +/// Type level support struct +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub struct SeverityHigh {} +impl HasSeverity for SeverityHigh { + const SEVERITY: Severity = Severity::High; +} + +pub trait GenericEvent: EcssEnumeration + Copy + Clone { + type Raw; + type GroupId; + type UniqueId; + + fn raw(&self) -> Self::Raw; + fn severity(&self) -> Severity; + fn group_id(&self) -> Self::GroupId; + fn unique_id(&self) -> Self::UniqueId; + + fn raw_as_largest_type(&self) -> LargestEventRaw; + fn group_id_as_largest_type(&self) -> LargestGroupIdRaw; +} + +impl TryFrom for Severity { + type Error = (); + + fn try_from(value: u8) -> Result { + match value { + x if x == Severity::Info as u8 => Ok(Severity::Info), + x if x == Severity::Low as u8 => Ok(Severity::Low), + x if x == Severity::Medium as u8 => Ok(Severity::Medium), + x if x == Severity::High as u8 => Ok(Severity::High), + _ => Err(()), + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +struct EventBase { + severity: Severity, + group_id: GroupId, + unique_id: UniqueId, + phantom: PhantomData, +} + +impl EventBase { + fn write_to_bytes( + &self, + raw: Raw, + buf: &mut [u8], + width: usize, + ) -> Result { + if buf.len() < width { + return Err(ByteConversionError::ToSliceTooSmall { + found: buf.len(), + expected: width, + }); + } + buf.copy_from_slice(raw.to_be_bytes().as_ref()); + Ok(raw.written_len()) + } +} + +impl EventBase { + #[inline] + fn raw(&self) -> u32 { + ((self.severity as u32) << 30) | ((self.group_id as u32) << 16) | self.unique_id as u32 + } +} + +impl EventBase { + #[inline] + fn raw(&self) -> u16 { + ((self.severity as u16) << 14) | ((self.group_id as u16) << 8) | self.unique_id as u16 + } +} + +impl EventBase { + #[inline] + pub fn severity(&self) -> Severity { + self.severity + } +} + +impl EventBase { + #[inline] + pub fn unique_id(&self) -> u16 { + self.unique_id + } +} + +impl EventBase { + #[inline] + pub fn unique_id(&self) -> u8 { + self.unique_id + } +} + +impl EventBase { + #[inline] + pub fn group_id(&self) -> u16 { + self.group_id + } +} + +impl EventBase { + #[inline] + pub fn group_id(&self) -> u8 { + self.group_id + } +} + +macro_rules! event_provider_impl { + () => { + #[inline] + fn raw(&self) -> Self::Raw { + self.base.raw() + } + + /// Retrieve the severity of an event. Returns None if that severity bit field of the raw event + /// ID is invalid + #[inline] + fn severity(&self) -> Severity { + self.base.severity() + } + + #[inline] + fn group_id(&self) -> Self::GroupId { + self.base.group_id() + } + + #[inline] + fn unique_id(&self) -> Self::UniqueId { + self.base.unique_id() + } + }; +} + +macro_rules! impl_event_provider { + ($BaseIdent: ident, $TypedIdent: ident, $raw: ty, $gid: ty, $uid: ty) => { + impl GenericEvent for $BaseIdent { + type Raw = $raw; + type GroupId = $gid; + type UniqueId = $uid; + + event_provider_impl!(); + + fn raw_as_largest_type(&self) -> LargestEventRaw { + self.raw().into() + } + + fn group_id_as_largest_type(&self) -> LargestGroupIdRaw { + self.group_id().into() + } + } + + impl GenericEvent for $TypedIdent { + type Raw = $raw; + type GroupId = $gid; + type UniqueId = $uid; + + delegate!(to self.event { + fn raw(&self) -> Self::Raw; + fn severity(&self) -> Severity; + fn group_id(&self) -> Self::GroupId; + fn unique_id(&self) -> Self::UniqueId; + fn raw_as_largest_type(&self) -> LargestEventRaw; + fn group_id_as_largest_type(&self) -> LargestGroupIdRaw; + }); + } + } +} + +macro_rules! try_from_impls { + ($SevIdent: ident, $severity: path, $raw: ty, $TypedSevIdent: ident) => { + impl TryFrom<$raw> for $TypedSevIdent<$SevIdent> { + type Error = Severity; + + fn try_from(raw: $raw) -> Result { + Self::try_from_generic($severity, raw) + } + } + }; +} + +macro_rules! const_from_fn { + ($from_fn_name: ident, $TypedIdent: ident, $SevIdent: ident) => { + pub const fn $from_fn_name(event: $TypedIdent<$SevIdent>) -> Self { + Self { + base: event.event.base, + } + } + }; +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct EventU32 { + base: EventBase, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct EventU32TypedSev { + event: EventU32, + phantom: PhantomData, +} + +impl From> for EventU32 { + fn from(e: EventU32TypedSev) -> Self { + Self { base: e.event.base } + } +} + +impl AsRef for EventU32TypedSev { + fn as_ref(&self) -> &EventU32 { + &self.event + } +} + +impl AsMut for EventU32TypedSev { + fn as_mut(&mut self) -> &mut EventU32 { + &mut self.event + } +} + +impl_event_provider!(EventU32, EventU32TypedSev, u32, u16, u16); + +impl EventU32 { + /// Generate an event. The raw representation of an event has 32 bits. + /// If the passed group ID is invalid (too large), None wil be returned + /// + /// # Parameter + /// + /// * `severity`: Each event has a [severity][Severity]. The raw value of the severity will + /// be stored inside the uppermost 2 bits of the raw event ID + /// * `group_id`: Related events can be grouped using a group ID. The group ID will occupy the + /// next 14 bits after the severity. Therefore, the size is limited by dec 16383 hex 0x3FFF. + /// * `unique_id`: Each event has a unique 16 bit ID occupying the last 16 bits of the + /// raw event ID + pub fn new_checked( + severity: Severity, + group_id: ::GroupId, + unique_id: ::UniqueId, + ) -> Option { + if group_id > MAX_GROUP_ID_U32_EVENT { + return None; + } + Some(Self { + base: EventBase { + severity, + group_id, + unique_id, + phantom: PhantomData, + }, + }) + } + + /// This constructor will panic if the passed group is is larger than [MAX_GROUP_ID_U32_EVENT]. + pub const fn new( + severity: Severity, + group_id: ::GroupId, + unique_id: ::UniqueId, + ) -> Self { + if group_id > MAX_GROUP_ID_U32_EVENT { + panic!("Group ID too large"); + } + Self { + base: EventBase { + severity, + group_id, + unique_id, + phantom: PhantomData, + }, + } + } + + pub fn from_be_bytes(bytes: [u8; 4]) -> Self { + Self::from(u32::from_be_bytes(bytes)) + } + + const_from_fn!(const_from_info, EventU32TypedSev, SeverityInfo); + const_from_fn!(const_from_low, EventU32TypedSev, SeverityLow); + const_from_fn!(const_from_medium, EventU32TypedSev, SeverityMedium); + const_from_fn!(const_from_high, EventU32TypedSev, SeverityHigh); +} + +impl From for EventU32 { + fn from(raw: u32) -> Self { + // Severity conversion from u8 should never fail + let severity = Severity::try_from(((raw >> 30) & 0b11) as u8).unwrap(); + let group_id = ((raw >> 16) & 0x3FFF) as u16; + let unique_id = (raw & 0xFFFF) as u16; + // Sanitized input, should never fail + Self::new(severity, group_id, unique_id) + } +} + +impl UnsignedEnum for EventU32 { + fn size(&self) -> usize { + core::mem::size_of::() + } + + fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { + self.base.write_to_bytes(self.raw(), buf, self.size()) + } + + fn value(&self) -> u64 { + self.raw().into() + } +} + +impl EcssEnumeration for EventU32 { + fn pfc(&self) -> u8 { + u32::BITS as u8 + } +} + +impl EventU32TypedSev { + /// This is similar to [EventU32::new] but the severity is a type generic, which allows to + /// have distinct types for events with different severities + pub fn new_checked( + group_id: ::GroupId, + unique_id: ::UniqueId, + ) -> Option { + let event = EventU32::new_checked(SEVERITY::SEVERITY, group_id, unique_id)?; + Some(Self { + event, + phantom: PhantomData, + }) + } + + /// This constructor will panic if the `group_id` is larger than [MAX_GROUP_ID_U32_EVENT]. + pub const fn new( + group_id: ::GroupId, + unique_id: ::UniqueId, + ) -> Self { + let event = EventU32::new(SEVERITY::SEVERITY, group_id, unique_id); + Self { + event, + phantom: PhantomData, + } + } + + fn try_from_generic(expected: Severity, raw: u32) -> Result { + let severity = Severity::try_from(((raw >> 30) & 0b11) as u8).unwrap(); + if severity != expected { + return Err(severity); + } + Ok(Self::new( + ((raw >> 16) & 0x3FFF) as u16, + (raw & 0xFFFF) as u16, + )) + } +} + +try_from_impls!(SeverityInfo, Severity::Info, u32, EventU32TypedSev); +try_from_impls!(SeverityLow, Severity::Low, u32, EventU32TypedSev); +try_from_impls!(SeverityMedium, Severity::Medium, u32, EventU32TypedSev); +try_from_impls!(SeverityHigh, Severity::High, u32, EventU32TypedSev); + +//noinspection RsTraitImplementation +impl UnsignedEnum for EventU32TypedSev { + delegate!(to self.event { + fn size(&self) -> usize; + fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result; + fn value(&self) -> u64; + }); +} + +//noinspection RsTraitImplementation +impl EcssEnumeration for EventU32TypedSev { + delegate!(to self.event { + fn pfc(&self) -> u8; + }); +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct EventU16 { + base: EventBase, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct EventU16TypedSev { + event: EventU16, + phantom: PhantomData, +} + +impl AsRef for EventU16TypedSev { + fn as_ref(&self) -> &EventU16 { + &self.event + } +} + +impl AsMut for EventU16TypedSev { + fn as_mut(&mut self) -> &mut EventU16 { + &mut self.event + } +} + +impl EventU16 { + /// Generate a small event. The raw representation of a small event has 16 bits. + /// If the passed group ID is invalid (too large), [None] wil be returned + /// + /// # Parameter + /// + /// * `severity`: Each event has a [severity][Severity]. The raw value of the severity will + /// be stored inside the uppermost 2 bits of the raw event ID + /// * `group_id`: Related events can be grouped using a group ID. The group ID will occupy the + /// next 6 bits after the severity. Therefore, the size is limited by dec 63 hex 0x3F. + /// * `unique_id`: Each event has a unique 8 bit ID occupying the last 8 bits of the + /// raw event ID + pub fn new_checked( + severity: Severity, + group_id: ::GroupId, + unique_id: ::UniqueId, + ) -> Option { + if group_id > (2u8.pow(6) - 1) { + return None; + } + Some(Self { + base: EventBase { + severity, + group_id, + unique_id, + phantom: Default::default(), + }, + }) + } + + /// This constructor will panic if the `group_id` is larger than [MAX_GROUP_ID_U16_EVENT]. + pub const fn new( + severity: Severity, + group_id: ::GroupId, + unique_id: ::UniqueId, + ) -> Self { + if group_id > (2u8.pow(6) - 1) { + panic!("Group ID too large"); + } + Self { + base: EventBase { + severity, + group_id, + unique_id, + phantom: PhantomData, + }, + } + } + pub fn from_be_bytes(bytes: [u8; 2]) -> Self { + Self::from(u16::from_be_bytes(bytes)) + } + + const_from_fn!(const_from_info, EventU16TypedSev, SeverityInfo); + const_from_fn!(const_from_low, EventU16TypedSev, SeverityLow); + const_from_fn!(const_from_medium, EventU16TypedSev, SeverityMedium); + const_from_fn!(const_from_high, EventU16TypedSev, SeverityHigh); +} + +impl From for EventU16 { + fn from(raw: ::Raw) -> Self { + let severity = Severity::try_from(((raw >> 14) & 0b11) as u8).unwrap(); + let group_id = ((raw >> 8) & 0x3F) as u8; + let unique_id = (raw & 0xFF) as u8; + // Sanitized input, new call should never fail + Self::new(severity, group_id, unique_id) + } +} + +impl UnsignedEnum for EventU16 { + fn size(&self) -> usize { + core::mem::size_of::() + } + + fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { + self.base.write_to_bytes(self.raw(), buf, self.size()) + } + + fn value(&self) -> u64 { + self.raw().into() + } +} +impl EcssEnumeration for EventU16 { + #[inline] + fn pfc(&self) -> u8 { + u16::BITS as u8 + } +} + +impl EventU16TypedSev { + /// This is similar to [EventU16::new] but the severity is a type generic, which allows to + /// have distinct types for events with different severities + pub fn new_checked( + group_id: ::GroupId, + unique_id: ::UniqueId, + ) -> Option { + let event = EventU16::new_checked(SEVERITY::SEVERITY, group_id, unique_id)?; + Some(Self { + event, + phantom: PhantomData, + }) + } + + /// This constructor will panic if the `group_id` is larger than [MAX_GROUP_ID_U16_EVENT]. + pub const fn new( + group_id: ::GroupId, + unique_id: ::UniqueId, + ) -> Self { + let event = EventU16::new(SEVERITY::SEVERITY, group_id, unique_id); + Self { + event, + phantom: PhantomData, + } + } + + fn try_from_generic(expected: Severity, raw: u16) -> Result { + let severity = Severity::try_from(((raw >> 14) & 0b11) as u8).unwrap(); + if severity != expected { + return Err(severity); + } + Ok(Self::new(((raw >> 8) & 0x3F) as u8, (raw & 0xFF) as u8)) + } +} + +impl_event_provider!(EventU16, EventU16TypedSev, u16, u8, u8); + +//noinspection RsTraitImplementation +impl UnsignedEnum for EventU16TypedSev { + delegate!(to self.event { + fn size(&self) -> usize; + fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result; + fn value(&self) -> u64; + }); +} + +//noinspection RsTraitImplementation +impl EcssEnumeration for EventU16TypedSev { + delegate!(to self.event { + fn pfc(&self) -> u8; + }); +} + +try_from_impls!(SeverityInfo, Severity::Info, u16, EventU16TypedSev); +try_from_impls!(SeverityLow, Severity::Low, u16, EventU16TypedSev); +try_from_impls!(SeverityMedium, Severity::Medium, u16, EventU16TypedSev); +try_from_impls!(SeverityHigh, Severity::High, u16, EventU16TypedSev); + +impl PartialEq for EventU32TypedSev { + #[inline] + fn eq(&self, other: &EventU32) -> bool { + self.raw() == other.raw() + } +} + +impl PartialEq> for EventU32 { + #[inline] + fn eq(&self, other: &EventU32TypedSev) -> bool { + self.raw() == other.raw() + } +} + +impl PartialEq for EventU16TypedSev { + #[inline] + fn eq(&self, other: &EventU16) -> bool { + self.raw() == other.raw() + } +} + +impl PartialEq> for EventU16 { + #[inline] + fn eq(&self, other: &EventU16TypedSev) -> bool { + self.raw() == other.raw() + } +} + +#[cfg(test)] +mod tests { + use super::EventU32TypedSev; + use super::*; + use spacepackets::ByteConversionError; + use std::mem::size_of; + + fn assert_size(_: T, val: usize) { + assert_eq!(size_of::(), val); + } + + const INFO_EVENT: EventU32TypedSev = EventU32TypedSev::new(0, 0); + const INFO_EVENT_SMALL: EventU16TypedSev = EventU16TypedSev::new(0, 0); + const HIGH_SEV_EVENT: EventU32TypedSev = EventU32TypedSev::new(0x3FFF, 0xFFFF); + const HIGH_SEV_EVENT_SMALL: EventU16TypedSev = EventU16TypedSev::new(0x3F, 0xff); + + /// This working is a test in itself. + const INFO_REDUCED: EventU32 = EventU32::const_from_info(INFO_EVENT); + + #[test] + fn test_normal_from_raw_conversion() { + let conv_from_raw = EventU32TypedSev::::try_from(INFO_EVENT.raw()) + .expect("Creating typed EventU32 failed"); + assert_eq!(conv_from_raw, INFO_EVENT); + } + + #[test] + fn test_small_from_raw_conversion() { + let conv_from_raw = EventU16TypedSev::::try_from(INFO_EVENT_SMALL.raw()) + .expect("Creating typed EventU16 failed"); + assert_eq!(conv_from_raw, INFO_EVENT_SMALL); + } + + #[test] + fn verify_normal_size() { + assert_size(INFO_EVENT.raw(), 4) + } + + #[test] + fn verify_small_size() { + assert_size(INFO_EVENT_SMALL.raw(), 2) + } + + #[test] + fn test_normal_event_getters() { + assert_eq!(INFO_EVENT.severity(), Severity::Info); + assert_eq!(INFO_EVENT.unique_id(), 0); + assert_eq!(INFO_EVENT.group_id(), 0); + let raw_event = INFO_EVENT.raw(); + assert_eq!(raw_event, 0x00000000); + } + + #[test] + fn test_small_event_getters() { + assert_eq!(INFO_EVENT_SMALL.severity(), Severity::Info); + assert_eq!(INFO_EVENT_SMALL.unique_id(), 0); + assert_eq!(INFO_EVENT_SMALL.group_id(), 0); + let raw_event = INFO_EVENT_SMALL.raw(); + assert_eq!(raw_event, 0x00000000); + } + + #[test] + fn all_ones_event_regular() { + assert_eq!(HIGH_SEV_EVENT.severity(), Severity::High); + assert_eq!(HIGH_SEV_EVENT.group_id(), 0x3FFF); + assert_eq!(HIGH_SEV_EVENT.unique_id(), 0xFFFF); + let raw_event = HIGH_SEV_EVENT.raw(); + assert_eq!(raw_event, 0xFFFFFFFF); + } + + #[test] + fn all_ones_event_small() { + assert_eq!(HIGH_SEV_EVENT_SMALL.severity(), Severity::High); + assert_eq!(HIGH_SEV_EVENT_SMALL.group_id(), 0x3F); + assert_eq!(HIGH_SEV_EVENT_SMALL.unique_id(), 0xFF); + let raw_event = HIGH_SEV_EVENT_SMALL.raw(); + assert_eq!(raw_event, 0xFFFF); + } + + #[test] + fn invalid_group_id_normal() { + assert!(EventU32TypedSev::::new_checked(2_u16.pow(14), 0).is_none()); + } + + #[test] + fn invalid_group_id_small() { + assert!(EventU16TypedSev::::new_checked(2_u8.pow(6), 0).is_none()); + } + + #[test] + fn regular_new() { + assert_eq!( + EventU32TypedSev::::new_checked(0, 0) + .expect("Creating regular event failed"), + INFO_EVENT + ); + } + + #[test] + fn small_new() { + assert_eq!( + EventU16TypedSev::::new_checked(0, 0) + .expect("Creating regular event failed"), + INFO_EVENT_SMALL + ); + } + + #[test] + fn as_largest_type() { + let event_raw = HIGH_SEV_EVENT.raw_as_largest_type(); + assert_size(event_raw, 4); + assert_eq!(event_raw, 0xFFFFFFFF); + } + + #[test] + fn as_largest_type_for_small_event() { + let event_raw = HIGH_SEV_EVENT_SMALL.raw_as_largest_type(); + assert_size(event_raw, 4); + assert_eq!(event_raw, 0xFFFF); + } + + #[test] + fn as_largest_group_id() { + let group_id = HIGH_SEV_EVENT.group_id_as_largest_type(); + assert_size(group_id, 2); + assert_eq!(group_id, 0x3FFF); + } + + #[test] + fn as_largest_group_id_small_event() { + let group_id = HIGH_SEV_EVENT_SMALL.group_id_as_largest_type(); + assert_size(group_id, 2); + assert_eq!(group_id, 0x3F); + } + + #[test] + fn write_to_buf() { + let mut buf: [u8; 4] = [0; 4]; + assert!(HIGH_SEV_EVENT.write_to_be_bytes(&mut buf).is_ok()); + let val_from_raw = u32::from_be_bytes(buf); + assert_eq!(val_from_raw, 0xFFFFFFFF); + let event_read_back = EventU32::from_be_bytes(buf); + assert_eq!(event_read_back, HIGH_SEV_EVENT); + } + + #[test] + fn write_to_buf_small() { + let mut buf: [u8; 2] = [0; 2]; + assert!(HIGH_SEV_EVENT_SMALL.write_to_be_bytes(&mut buf).is_ok()); + let val_from_raw = u16::from_be_bytes(buf); + assert_eq!(val_from_raw, 0xFFFF); + let event_read_back = EventU16::from_be_bytes(buf); + assert_eq!(event_read_back, HIGH_SEV_EVENT_SMALL); + } + + #[test] + fn write_to_buf_insufficient_buf() { + let mut buf: [u8; 3] = [0; 3]; + let err = HIGH_SEV_EVENT.write_to_be_bytes(&mut buf); + assert!(err.is_err()); + let err = err.unwrap_err(); + if let ByteConversionError::ToSliceTooSmall { found, expected } = err { + assert_eq!(expected, 4); + assert_eq!(found, 3); + } + } + + #[test] + fn write_to_buf_small_insufficient_buf() { + let mut buf: [u8; 1] = [0; 1]; + let err = HIGH_SEV_EVENT_SMALL.write_to_be_bytes(&mut buf); + assert!(err.is_err()); + let err = err.unwrap_err(); + if let ByteConversionError::ToSliceTooSmall { found, expected } = err { + assert_eq!(expected, 2); + assert_eq!(found, 1); + } + } + + #[test] + fn severity_from_invalid_raw_val() { + let invalid = 0xFF; + assert!(Severity::try_from(invalid).is_err()); + let invalid = Severity::High as u8 + 1; + assert!(Severity::try_from(invalid).is_err()); + } + + #[test] + fn reduction() { + let event = EventU32TypedSev::::new(1, 1); + let raw = event.raw(); + let reduced: EventU32 = event.into(); + assert_eq!(reduced.group_id(), 1); + assert_eq!(reduced.unique_id(), 1); + assert_eq!(raw, reduced.raw()); + } + + #[test] + fn const_reducation() { + assert_eq!(INFO_REDUCED.raw(), INFO_EVENT.raw()); + } +} diff --git a/satrs/src/lib.rs b/satrs/src/lib.rs index 5b81fe2..22b0cee 100644 --- a/satrs/src/lib.rs +++ b/satrs/src/lib.rs @@ -15,7 +15,7 @@ //! the [ECSS PUS C standard](https://ecss.nl/standard/ecss-e-st-70-41c-space-engineering-telemetry-and-telecommand-packet-utilization-15-april-2016/). #![no_std] #![cfg_attr(docsrs, feature(doc_auto_cfg))] -#[cfg(feature = "alloc")] +#[cfg(any(feature = "alloc", test))] extern crate alloc; #[cfg(feature = "alloc")] extern crate downcast_rs; @@ -27,7 +27,9 @@ pub mod action; pub mod dev_mgmt; pub mod encoding; pub mod event_man; +pub mod event_man_legacy; pub mod events; +pub mod events_legacy; #[cfg(feature = "std")] pub mod executable; pub mod hal; diff --git a/satrs/src/pool.rs b/satrs/src/pool.rs index 95bdeca..c0c3c09 100644 --- a/satrs/src/pool.rs +++ b/satrs/src/pool.rs @@ -258,6 +258,9 @@ pub trait PoolProvider { /// Delete data inside the pool given a [PoolAddr]. fn delete(&mut self, addr: PoolAddr) -> Result<(), PoolError>; + + fn clear(&mut self) -> Result<(), PoolError>; + fn has_element_at(&self, addr: &PoolAddr) -> Result; /// Retrieve the length of the data at the given store address. @@ -714,6 +717,13 @@ pub mod heapless_mod { Ok(()) } + fn clear(&mut self) -> Result<(), PoolError> { + for size in self.sizes_lists.iter_mut() { + size.fill(STORE_FREE); + } + Ok(()) + } + fn has_element_at(&self, addr: &PoolAddr) -> Result { let addr = StaticPoolAddr::from(*addr); self.validate_addr(&addr)?; @@ -1055,6 +1065,13 @@ mod alloc_mod { _ => size, }) } + + fn clear(&mut self) -> Result<(), PoolError> { + for size in self.sizes_lists.iter_mut() { + size.fill(STORE_FREE); + } + Ok(()) + } } impl PoolProviderWithGuards for StaticMemoryPool { @@ -1597,223 +1614,228 @@ mod tests { mod heapless_tests { use super::*; use crate::static_subpool; - use std::cell::UnsafeCell; - use std::sync::Mutex; const SUBPOOL_1_BLOCK_SIZE: usize = 4; const SUBPOOL_1_NUM_ELEMENTS: u16 = 4; - static SUBPOOL_1: static_cell::ConstStaticCell< - [u8; SUBPOOL_1_NUM_ELEMENTS as usize * SUBPOOL_1_BLOCK_SIZE], - > = static_cell::ConstStaticCell::new( - [0; SUBPOOL_1_NUM_ELEMENTS as usize * SUBPOOL_1_BLOCK_SIZE], - ); - - static SUBPOOL_1_SIZES: Mutex> = - Mutex::new(UnsafeCell::new( - [STORE_FREE; SUBPOOL_1_NUM_ELEMENTS as usize], - )); - const SUBPOOL_2_NUM_ELEMENTS: u16 = 2; const SUBPOOL_2_BLOCK_SIZE: usize = 8; - static SUBPOOL_2: static_cell::ConstStaticCell< - [u8; SUBPOOL_2_NUM_ELEMENTS as usize * SUBPOOL_2_BLOCK_SIZE], - > = static_cell::ConstStaticCell::new( - [0; SUBPOOL_2_NUM_ELEMENTS as usize * SUBPOOL_2_BLOCK_SIZE], - ); - static SUBPOOL_2_SIZES: static_cell::ConstStaticCell< - [usize; SUBPOOL_2_NUM_ELEMENTS as usize], - > = static_cell::ConstStaticCell::new([STORE_FREE; SUBPOOL_2_NUM_ELEMENTS as usize]); const SUBPOOL_3_NUM_ELEMENTS: u16 = 1; const SUBPOOL_3_BLOCK_SIZE: usize = 16; - static_subpool!( - SUBPOOL_3, - SUBPOOL_3_SIZES, - SUBPOOL_3_NUM_ELEMENTS as usize, - SUBPOOL_3_BLOCK_SIZE - ); const SUBPOOL_4_NUM_ELEMENTS: u16 = 2; const SUBPOOL_4_BLOCK_SIZE: usize = 16; - static_subpool!( - SUBPOOL_4, - SUBPOOL_4_SIZES, - SUBPOOL_4_NUM_ELEMENTS as usize, - SUBPOOL_4_BLOCK_SIZE - ); const SUBPOOL_5_NUM_ELEMENTS: u16 = 1; const SUBPOOL_5_BLOCK_SIZE: usize = 8; - static_subpool!( - SUBPOOL_5, - SUBPOOL_5_SIZES, - SUBPOOL_5_NUM_ELEMENTS as usize, - SUBPOOL_5_BLOCK_SIZE - ); const SUBPOOL_6_NUM_ELEMENTS: u16 = 1; const SUBPOOL_6_BLOCK_SIZE: usize = 12; - static_subpool!( - SUBPOOL_6, - SUBPOOL_6_SIZES, - SUBPOOL_6_NUM_ELEMENTS as usize, - SUBPOOL_6_BLOCK_SIZE - ); - fn small_heapless_pool() -> StaticHeaplessMemoryPool<3> { - let mut heapless_pool: StaticHeaplessMemoryPool<3> = - StaticHeaplessMemoryPool::new(false); - assert!( - heapless_pool - .grow( - SUBPOOL_1.take(), - unsafe { &mut *SUBPOOL_1_SIZES.lock().unwrap().get() }, - SUBPOOL_1_NUM_ELEMENTS, - true - ) - .is_ok() - ); - assert!( - heapless_pool - .grow( - SUBPOOL_2.take(), - SUBPOOL_2_SIZES.take(), - SUBPOOL_2_NUM_ELEMENTS, - true - ) - .is_ok() - ); - assert!( - heapless_pool - .grow( - SUBPOOL_3.take(), - SUBPOOL_3_SIZES.take(), - SUBPOOL_3_NUM_ELEMENTS, - true - ) - .is_ok() - ); - heapless_pool + macro_rules! make_heapless_pool { + ($prefix:ident) => {{ + paste::paste! { + static [<$prefix _SUBPOOL_1>]: static_cell::ConstStaticCell< + [u8; SUBPOOL_1_NUM_ELEMENTS as usize * SUBPOOL_1_BLOCK_SIZE], + > = static_cell::ConstStaticCell::new( + [0; SUBPOOL_1_NUM_ELEMENTS as usize * SUBPOOL_1_BLOCK_SIZE], + ); + + static [<$prefix _SUBPOOL_1_SIZES>]: std::sync::Mutex< + std::cell::UnsafeCell<[usize; SUBPOOL_1_NUM_ELEMENTS as usize]> + > = std::sync::Mutex::new( + std::cell::UnsafeCell::new([STORE_FREE; SUBPOOL_1_NUM_ELEMENTS as usize]) + ); + + static [<$prefix _SUBPOOL_2>]: static_cell::ConstStaticCell< + [u8; SUBPOOL_2_NUM_ELEMENTS as usize * SUBPOOL_2_BLOCK_SIZE], + > = static_cell::ConstStaticCell::new( + [0; SUBPOOL_2_NUM_ELEMENTS as usize * SUBPOOL_2_BLOCK_SIZE], + ); + + static [<$prefix _SUBPOOL_2_SIZES>]: static_cell::ConstStaticCell< + [usize; SUBPOOL_2_NUM_ELEMENTS as usize], + > = static_cell::ConstStaticCell::new( + [STORE_FREE; SUBPOOL_2_NUM_ELEMENTS as usize] + ); + + static [<$prefix _SUBPOOL_3>]: static_cell::ConstStaticCell< + [u8; SUBPOOL_3_NUM_ELEMENTS as usize * SUBPOOL_3_BLOCK_SIZE], + > = static_cell::ConstStaticCell::new( + [0; SUBPOOL_3_NUM_ELEMENTS as usize * SUBPOOL_3_BLOCK_SIZE], + ); + + static [<$prefix _SUBPOOL_3_SIZES>]: static_cell::ConstStaticCell< + [usize; SUBPOOL_3_NUM_ELEMENTS as usize], + > = static_cell::ConstStaticCell::new( + [STORE_FREE; SUBPOOL_3_NUM_ELEMENTS as usize] + ); + + let mut heapless_pool: StaticHeaplessMemoryPool<3> = + StaticHeaplessMemoryPool::new(false); + + heapless_pool + .grow( + [<$prefix _SUBPOOL_1>].take(), + unsafe { &mut *[<$prefix _SUBPOOL_1_SIZES>].lock().unwrap().get() }, + SUBPOOL_1_NUM_ELEMENTS, + true + ) + .unwrap(); + + heapless_pool + .grow( + [<$prefix _SUBPOOL_2>].take(), + [<$prefix _SUBPOOL_2_SIZES>].take(), + SUBPOOL_2_NUM_ELEMENTS, + true + ) + .unwrap(); + + heapless_pool + .grow( + [<$prefix _SUBPOOL_3>].take(), + [<$prefix _SUBPOOL_3_SIZES>].take(), + SUBPOOL_3_NUM_ELEMENTS, + true + ) + .unwrap(); + + heapless_pool + } + }}; } #[test] fn test_heapless_add_and_read() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T0); generic_test_add_and_read::<16>(&mut pool_provider); } #[test] fn test_add_smaller_than_full_slot() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T1); generic_test_add_smaller_than_full_slot(&mut pool_provider); } #[test] fn test_delete() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T2); generic_test_delete(&mut pool_provider); } #[test] fn test_modify() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T3); generic_test_modify(&mut pool_provider); } #[test] fn test_consecutive_reservation() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T4); generic_test_consecutive_reservation(&mut pool_provider); } #[test] fn test_read_does_not_exist() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T5); generic_test_read_does_not_exist(&mut pool_provider); } #[test] fn test_store_full() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T6); generic_test_store_full(&mut pool_provider); } #[test] fn test_invalid_pool_idx() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T7); generic_test_invalid_pool_idx(&mut pool_provider); } #[test] fn test_invalid_packet_idx() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T8); generic_test_invalid_packet_idx(&mut pool_provider); } #[test] fn test_add_too_large() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T9); generic_test_add_too_large(&mut pool_provider); } #[test] fn test_data_too_large_1() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T10); generic_test_data_too_large_1(&mut pool_provider); } #[test] fn test_free_element_too_large() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T11); generic_test_free_element_too_large(&mut pool_provider); } #[test] fn test_pool_guard_deletion_man_creation() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T12); generic_test_pool_guard_deletion_man_creation(&mut pool_provider); } #[test] fn test_pool_guard_deletion() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T13); generic_test_pool_guard_deletion(&mut pool_provider); } #[test] fn test_pool_guard_with_release() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T14); generic_test_pool_guard_with_release(&mut pool_provider); } #[test] fn test_pool_modify_guard_man_creation() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T15); generic_test_pool_modify_guard_man_creation(&mut pool_provider); } #[test] fn test_pool_modify_guard() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T16); generic_test_pool_modify_guard(&mut pool_provider); } #[test] fn modify_pool_index_above_0() { - let mut pool_provider = small_heapless_pool(); + let mut pool_provider = make_heapless_pool!(T17); generic_modify_pool_index_above_0(&mut pool_provider); } #[test] fn test_spills_to_higher_subpools() { + static_subpool!( + SUBPOOL_2_T18, + SUBPOOL_2_SIZES_T18, + SUBPOOL_2_NUM_ELEMENTS as usize, + SUBPOOL_2_BLOCK_SIZE + ); + static_subpool!( + SUBPOOL_4_T18, + SUBPOOL_4_SIZES_T18, + SUBPOOL_4_NUM_ELEMENTS as usize, + SUBPOOL_4_BLOCK_SIZE + ); let mut heapless_pool: StaticHeaplessMemoryPool<2> = StaticHeaplessMemoryPool::new(true); assert!( heapless_pool .grow( - SUBPOOL_2.take(), - SUBPOOL_2_SIZES.take(), + SUBPOOL_2_T18.take(), + SUBPOOL_2_SIZES_T18.take(), SUBPOOL_2_NUM_ELEMENTS, true ) @@ -1822,8 +1844,8 @@ mod tests { assert!( heapless_pool .grow( - SUBPOOL_4.take(), - SUBPOOL_4_SIZES.take(), + SUBPOOL_4_T18.take(), + SUBPOOL_4_SIZES_T18.take(), SUBPOOL_4_NUM_ELEMENTS, true ) @@ -1836,6 +1858,18 @@ mod tests { fn test_spillage_fails_as_well() { let mut heapless_pool: StaticHeaplessMemoryPool<2> = StaticHeaplessMemoryPool::new(true); + static_subpool!( + SUBPOOL_5, + SUBPOOL_5_SIZES, + SUBPOOL_5_NUM_ELEMENTS as usize, + SUBPOOL_5_BLOCK_SIZE + ); + static_subpool!( + SUBPOOL_3, + SUBPOOL_3_SIZES, + SUBPOOL_3_NUM_ELEMENTS as usize, + SUBPOOL_3_BLOCK_SIZE + ); assert!( heapless_pool .grow( @@ -1863,6 +1897,24 @@ mod tests { fn test_spillage_works_across_multiple_subpools() { let mut heapless_pool: StaticHeaplessMemoryPool<3> = StaticHeaplessMemoryPool::new(true); + static_subpool!( + SUBPOOL_3, + SUBPOOL_3_SIZES, + SUBPOOL_3_NUM_ELEMENTS as usize, + SUBPOOL_3_BLOCK_SIZE + ); + static_subpool!( + SUBPOOL_5, + SUBPOOL_5_SIZES, + SUBPOOL_5_NUM_ELEMENTS as usize, + SUBPOOL_5_BLOCK_SIZE + ); + static_subpool!( + SUBPOOL_6, + SUBPOOL_6_SIZES, + SUBPOOL_6_NUM_ELEMENTS as usize, + SUBPOOL_6_BLOCK_SIZE + ); assert!( heapless_pool .grow( @@ -1898,6 +1950,24 @@ mod tests { #[test] fn test_spillage_fails_across_multiple_subpools() { + static_subpool!( + SUBPOOL_3, + SUBPOOL_3_SIZES, + SUBPOOL_3_NUM_ELEMENTS as usize, + SUBPOOL_3_BLOCK_SIZE + ); + static_subpool!( + SUBPOOL_5, + SUBPOOL_5_SIZES, + SUBPOOL_5_NUM_ELEMENTS as usize, + SUBPOOL_5_BLOCK_SIZE + ); + static_subpool!( + SUBPOOL_6, + SUBPOOL_6_SIZES, + SUBPOOL_6_NUM_ELEMENTS as usize, + SUBPOOL_6_BLOCK_SIZE + ); let mut heapless_pool: StaticHeaplessMemoryPool<3> = StaticHeaplessMemoryPool::new(true); assert!( diff --git a/satrs/src/pus/event.rs b/satrs/src/pus/event.rs index 520e819..ecf4b4f 100644 --- a/satrs/src/pus/event.rs +++ b/satrs/src/pus/event.rs @@ -265,7 +265,7 @@ mod alloc_mod { mod tests { use super::*; use crate::ComponentId; - use crate::events::{EventU32, Severity}; + use crate::events_legacy::{EventU32, Severity}; use crate::pus::test_util::TEST_COMPONENT_ID_0; use crate::pus::tests::CommonTmInfo; use crate::pus::{ChannelWithId, EcssTmSender, EcssTmtcError, PusTmVariant}; diff --git a/satrs/src/pus/event_man.rs b/satrs/src/pus/event_man.rs index 5be5428..11af4d1 100644 --- a/satrs/src/pus/event_man.rs +++ b/satrs/src/pus/event_man.rs @@ -1,6 +1,6 @@ -use crate::events::{EventU32, GenericEvent, Severity}; +use crate::events_legacy::{EventU32, GenericEvent, Severity}; #[cfg(feature = "alloc")] -use crate::events::{EventU32TypedSev, HasSeverity}; +use crate::events_legacy::{EventU32TypedSev, HasSeverity}; #[cfg(feature = "alloc")] use core::hash::Hash; #[cfg(feature = "alloc")] @@ -100,7 +100,7 @@ pub mod alloc_mod { use core::marker::PhantomData; use crate::{ - events::EventU16, + events_legacy::EventU16, params::{Params, WritableToBeBytes}, pus::event::{DummyEventHook, EventTmHook}, }; @@ -318,7 +318,7 @@ mod tests { use super::*; use crate::request::UniqueApidTargetId; - use crate::{events::SeverityInfo, tmtc::PacketAsVec}; + use crate::{events_legacy::SeverityInfo, tmtc::PacketAsVec}; use std::sync::mpsc::{self, TryRecvError}; const INFO_EVENT: EventU32TypedSev = EventU32TypedSev::::new(1, 0); diff --git a/satrs/src/pus/event_srv.rs b/satrs/src/pus/event_srv.rs index 63cd62b..74a0f58 100644 --- a/satrs/src/pus/event_srv.rs +++ b/satrs/src/pus/event_srv.rs @@ -1,4 +1,4 @@ -use crate::events::EventU32; +use crate::events_legacy::EventU32; use crate::pus::event_man::{EventRequest, EventRequestWithToken}; use crate::pus::verification::TcStateToken; use crate::pus::{DirectPusPacketHandlerResult, PartialPusHandlingError, PusPacketHandlingError}; @@ -168,7 +168,7 @@ mod tests { use crate::pus::{GenericConversionError, HandlingStatus, MpscTcReceiver}; use crate::tmtc::PacketSenderWithSharedPool; use crate::{ - events::EventU32, + events_legacy::EventU32, pus::{ DirectPusPacketHandlerResult, EcssTcInSharedPoolCacher, PusPacketHandlingError, event_man::EventRequestWithToken, @@ -179,7 +179,7 @@ mod tests { use super::PusEventServiceHandler; - const TEST_EVENT_0: EventU32 = EventU32::new(crate::events::Severity::Info, 5, 25); + const TEST_EVENT_0: EventU32 = EventU32::new(crate::events_legacy::Severity::Info, 5, 25); struct Pus5HandlerWithStoreTester { common: PusServiceHandlerWithSharedStoreCommon, diff --git a/satrs/tests/pus_autogen_events.rs b/satrs/tests/pus_autogen_events.rs deleted file mode 100644 index 22800de..0000000 --- a/satrs/tests/pus_autogen_events.rs +++ /dev/null @@ -1,94 +0,0 @@ -#![allow(dead_code, unused_imports)] - -use satrs::events::{ - EventU32, EventU32TypedSev, GenericEvent, HasSeverity, LargestEventRaw, LargestGroupIdRaw, - Severity, SeverityInfo, SeverityLow, SeverityMedium, -}; -use std::convert::AsRef; - -#[derive(Debug)] -struct GroupIdIntrospection { - name: &'static str, - id: LargestGroupIdRaw, -} - -#[derive(Debug)] -struct EventIntrospection { - name: &'static str, - group_id: GroupIdIntrospection, - event: &'static EventU32, - info: &'static str, -} - -//#[event(descr="This is some info event")] -const INFO_EVENT_0: EventU32TypedSev = EventU32TypedSev::new(0, 0); -const INFO_EVENT_0_ERASED: EventU32 = EventU32::const_from_info(INFO_EVENT_0); - -// This is ideally auto-generated -const INFO_EVENT_0_INTROSPECTION: EventIntrospection = EventIntrospection { - name: "INFO_EVENT_0", - group_id: GroupIdIntrospection { - id: 0, - name: "Group ID 0 without name", - }, - event: &INFO_EVENT_0_ERASED, - info: "This is some info event", -}; - -//#[event(descr="This is some low severity event")] -const SOME_LOW_SEV_EVENT: EventU32TypedSev = EventU32TypedSev::new(0, 12); - -//const EVENT_LIST: [&'static Event; 2] = [&INFO_EVENT_0, &SOME_LOW_SEV_EVENT]; - -//#[event_group] -const TEST_GROUP_NAME: u16 = 1; -// Auto-generated? -const TEST_GROUP_NAME_NAME: &str = "TEST_GROUP_NAME"; - -//#[event(desc="Some medium severity event")] -const MEDIUM_SEV_EVENT_IN_OTHER_GROUP: EventU32TypedSev = - EventU32TypedSev::new(TEST_GROUP_NAME, 0); -const MEDIUM_SEV_EVENT_IN_OTHER_GROUP_REDUCED: EventU32 = - EventU32::const_from_medium(MEDIUM_SEV_EVENT_IN_OTHER_GROUP); - -// Also auto-generated -const MEDIUM_SEV_EVENT_IN_OTHER_GROUP_INTROSPECTION: EventIntrospection = EventIntrospection { - name: "MEDIUM_SEV_EVENT_IN_OTHER_GROUP", - group_id: GroupIdIntrospection { - name: TEST_GROUP_NAME_NAME, - id: TEST_GROUP_NAME, - }, - event: &MEDIUM_SEV_EVENT_IN_OTHER_GROUP_REDUCED, - info: "Some medium severity event", -}; - -const CONST_SLICE: &[u8] = &[0, 1, 2, 3]; -const INTROSPECTION_FOR_TEST_GROUP_0: [&EventIntrospection; 2] = - [&INFO_EVENT_0_INTROSPECTION, &INFO_EVENT_0_INTROSPECTION]; - -//const INTROSPECTION_FOR_TABLE: &'static [&EventIntrospection] = &INTROSPECTION_FOR_TEST_GROUP_0; - -const INTROSPECTION_FOR_TEST_GROUP_NAME: [&EventIntrospection; 1] = - [&MEDIUM_SEV_EVENT_IN_OTHER_GROUP_INTROSPECTION]; -//const BLAH: &'static [&EventIntrospection] = &INTROSPECTION_FOR_TEST_GROUP_NAME; - -const ALL_EVENTS: [&[&EventIntrospection]; 2] = [ - &INTROSPECTION_FOR_TEST_GROUP_0, - &INTROSPECTION_FOR_TEST_GROUP_NAME, -]; - -#[test] -fn main() { - //let test = stringify!(INFO_EVENT); - //println!("{:?}", test); - //for event in EVENT_LIST { - // println!("{:?}", event); - //} - //for events in ALL_EVENTS.into_iter().flatten() { - // dbg!("{:?}", events); - //} - //for introspection_info in INTROSPECTION_FOR_TEST_GROUP { - // dbg!("{:?}", introspection_info); - //} - //let test_struct = -} diff --git a/satrs/tests/pus_events.rs b/satrs/tests/pus_events.rs index 3979dc7..0dd26dc 100644 --- a/satrs/tests/pus_events.rs +++ b/satrs/tests/pus_events.rs @@ -1,9 +1,9 @@ use arbitrary_int::u11; -use satrs::event_man::{ +use satrs::event_man_legacy::{ EventManagerWithMpsc, EventMessage, EventMessageU32, EventRoutingError, EventSendProvider, EventU32SenderMpsc, }; -use satrs::events::{EventU32, EventU32TypedSev, Severity, SeverityInfo}; +use satrs::events_legacy::{EventU32, EventU32TypedSev, Severity, SeverityInfo}; use satrs::params::U32Pair; use satrs::params::{Params, ParamsHeapless, WritableToBeBytes}; use satrs::pus::event_man::{DefaultPusEventReportingMap, EventReporter, PusEventTmCreatorWithMap};