basic PUS event manager
This commit is contained in:
parent
6fe3738364
commit
478673327b
@ -1,5 +1,5 @@
|
||||
//! [Event][crate::events::Event] management and forwarding
|
||||
use crate::events::{Event, EventProvider, EventSmall};
|
||||
use crate::events::{EventU16TypedSev, EventU32, GenericEvent, HasSeverity};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
@ -11,34 +11,34 @@ enum ListenerType {
|
||||
Group(u16),
|
||||
}
|
||||
|
||||
pub trait EventListener<Provider: EventProvider = Event> {
|
||||
pub trait EventListener<Provider: GenericEvent> {
|
||||
type Error;
|
||||
|
||||
fn id(&self) -> u32;
|
||||
fn send_to(&mut self, event: Provider) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
struct Listener<E, Provider: EventProvider = Event> {
|
||||
struct Listener<E, Provider: GenericEvent> {
|
||||
ltype: ListenerType,
|
||||
dest: Box<dyn EventListener<Provider, Error = E>>,
|
||||
}
|
||||
|
||||
pub trait ReceivesAllEvent<Provider: EventProvider = Event> {
|
||||
pub trait ReceivesAllEvent<Provider: GenericEvent> {
|
||||
fn receive(&mut self) -> Option<Provider>;
|
||||
}
|
||||
|
||||
pub struct EventManager<E, Provider: EventProvider = Event> {
|
||||
pub struct EventManager<E, Provider: GenericEvent> {
|
||||
listeners: HashMap<ListenerType, Vec<Listener<E, Provider>>>,
|
||||
event_receiver: Box<dyn ReceivesAllEvent<Provider>>,
|
||||
}
|
||||
|
||||
pub enum HandlerResult<Provider: EventProvider = Event> {
|
||||
pub enum HandlerResult<Provider: GenericEvent> {
|
||||
Empty,
|
||||
Handled(u32, Provider),
|
||||
}
|
||||
|
||||
impl<E> EventManager<E, Event> {
|
||||
pub fn new(event_receiver: Box<dyn ReceivesAllEvent<Event>>) -> Self {
|
||||
impl<E> EventManager<E, EventU32> {
|
||||
pub fn new(event_receiver: Box<dyn ReceivesAllEvent<EventU32>>) -> Self {
|
||||
EventManager {
|
||||
listeners: HashMap::new(),
|
||||
event_receiver,
|
||||
@ -46,43 +46,43 @@ impl<E> EventManager<E, Event> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> EventManager<E, Event> {
|
||||
impl<E> EventManager<E, EventU32> {
|
||||
pub fn subscribe_single(
|
||||
&mut self,
|
||||
event: Event,
|
||||
dest: impl EventListener<Event, Error = E> + 'static,
|
||||
event: EventU32,
|
||||
dest: impl EventListener<EventU32, Error = E> + 'static,
|
||||
) {
|
||||
self.update_listeners(ListenerType::Single(event.raw_as_largest_type()), dest);
|
||||
}
|
||||
|
||||
pub fn subscribe_group(
|
||||
&mut self,
|
||||
group_id: <Event as EventProvider>::GroupId,
|
||||
dest: impl EventListener<Event, Error = E> + 'static,
|
||||
group_id: <EventU32 as GenericEvent>::GroupId,
|
||||
dest: impl EventListener<EventU32, Error = E> + 'static,
|
||||
) {
|
||||
self.update_listeners(ListenerType::Group(group_id), dest);
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> EventManager<E, EventSmall> {
|
||||
impl<E, SEVERITY: HasSeverity + Copy> EventManager<E, EventU16TypedSev<SEVERITY>> {
|
||||
pub fn subscribe_single(
|
||||
&mut self,
|
||||
event: EventSmall,
|
||||
dest: impl EventListener<EventSmall, Error = E> + 'static,
|
||||
event: EventU16TypedSev<SEVERITY>,
|
||||
dest: impl EventListener<EventU16TypedSev<SEVERITY>, Error = E> + 'static,
|
||||
) {
|
||||
self.update_listeners(ListenerType::Single(event.raw_as_largest_type()), dest);
|
||||
}
|
||||
|
||||
pub fn subscribe_group(
|
||||
&mut self,
|
||||
group_id: <EventSmall as EventProvider>::GroupId,
|
||||
dest: impl EventListener<EventSmall, Error = E> + 'static,
|
||||
group_id: <EventU16TypedSev<SEVERITY> as GenericEvent>::GroupId,
|
||||
dest: impl EventListener<EventU16TypedSev<SEVERITY>, Error = E> + 'static,
|
||||
) {
|
||||
self.update_listeners(ListenerType::Group(group_id.into()), dest);
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, Provider: EventProvider> EventManager<E, Provider> {
|
||||
impl<E, Provider: GenericEvent + Copy> EventManager<E, Provider> {
|
||||
fn update_listeners(
|
||||
&mut self,
|
||||
key: ListenerType,
|
||||
@ -145,17 +145,17 @@ impl<E, Provider: EventProvider> EventManager<E, Provider> {
|
||||
mod tests {
|
||||
use super::{EventListener, HandlerResult, ReceivesAllEvent};
|
||||
use crate::event_man::EventManager;
|
||||
use crate::events::{Event, EventProvider, Severity};
|
||||
use crate::events::{EventU32, GenericEvent, Severity};
|
||||
use alloc::boxed::Box;
|
||||
use std::sync::mpsc::{channel, Receiver, SendError, Sender};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
struct EventReceiver {
|
||||
mpsc_receiver: Receiver<Event>,
|
||||
mpsc_receiver: Receiver<EventU32>,
|
||||
}
|
||||
impl ReceivesAllEvent<Event> for EventReceiver {
|
||||
fn receive(&mut self) -> Option<Event> {
|
||||
impl ReceivesAllEvent<EventU32> for EventReceiver {
|
||||
fn receive(&mut self) -> Option<EventU32> {
|
||||
self.mpsc_receiver.try_recv().ok()
|
||||
}
|
||||
}
|
||||
@ -163,21 +163,21 @@ mod tests {
|
||||
#[derive(Clone)]
|
||||
struct MpscEventSenderQueue {
|
||||
id: u32,
|
||||
mpsc_sender: Sender<Event>,
|
||||
mpsc_sender: Sender<EventU32>,
|
||||
}
|
||||
|
||||
impl EventListener<Event> for MpscEventSenderQueue {
|
||||
type Error = SendError<Event>;
|
||||
impl EventListener<EventU32> for MpscEventSenderQueue {
|
||||
type Error = SendError<EventU32>;
|
||||
|
||||
fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
fn send_to(&mut self, event: Event) -> Result<(), Self::Error> {
|
||||
fn send_to(&mut self, event: EventU32) -> Result<(), Self::Error> {
|
||||
self.mpsc_sender.send(event)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_next_event(expected: Event, receiver: &Receiver<Event>) {
|
||||
fn check_next_event(expected: EventU32, receiver: &Receiver<EventU32>) {
|
||||
for _ in 0..5 {
|
||||
if let Ok(event) = receiver.try_recv() {
|
||||
assert_eq!(event, expected);
|
||||
@ -187,7 +187,11 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_handled_event(res: HandlerResult, expected: Event, expected_num_sent: u32) {
|
||||
fn check_handled_event(
|
||||
res: HandlerResult<EventU32>,
|
||||
expected: EventU32,
|
||||
expected_num_sent: u32,
|
||||
) {
|
||||
assert!(matches!(res, HandlerResult::Handled { .. }));
|
||||
if let HandlerResult::Handled(num_recipients, event) = res {
|
||||
assert_eq!(event, expected);
|
||||
@ -201,10 +205,10 @@ mod tests {
|
||||
let event_man_receiver = EventReceiver {
|
||||
mpsc_receiver: manager_queue,
|
||||
};
|
||||
let mut event_man: EventManager<SendError<Event>, Event> =
|
||||
let mut event_man: EventManager<SendError<EventU32>, EventU32> =
|
||||
EventManager::new(Box::new(event_man_receiver));
|
||||
let event_grp_0 = Event::new(Severity::INFO, 0, 0).unwrap();
|
||||
let event_grp_1_0 = Event::new(Severity::HIGH, 1, 0).unwrap();
|
||||
let event_grp_0 = EventU32::new(Severity::INFO, 0, 0).unwrap();
|
||||
let event_grp_1_0 = EventU32::new(Severity::HIGH, 1, 0).unwrap();
|
||||
let (single_event_sender, single_event_receiver) = channel();
|
||||
let single_event_listener = MpscEventSenderQueue {
|
||||
id: 0,
|
||||
@ -244,15 +248,15 @@ mod tests {
|
||||
let event_man_receiver = EventReceiver {
|
||||
mpsc_receiver: manager_queue,
|
||||
};
|
||||
let mut event_man: EventManager<SendError<Event>, Event> =
|
||||
let mut event_man: EventManager<SendError<EventU32>, EventU32> =
|
||||
EventManager::new(Box::new(event_man_receiver));
|
||||
let res = event_man.try_event_handling();
|
||||
assert!(res.is_ok());
|
||||
let hres = res.unwrap();
|
||||
assert!(matches!(hres, HandlerResult::Empty));
|
||||
|
||||
let event_grp_0 = Event::new(Severity::INFO, 0, 0).unwrap();
|
||||
let event_grp_1_0 = Event::new(Severity::HIGH, 1, 0).unwrap();
|
||||
let event_grp_0 = EventU32::new(Severity::INFO, 0, 0).unwrap();
|
||||
let event_grp_1_0 = EventU32::new(Severity::HIGH, 1, 0).unwrap();
|
||||
let (event_grp_0_sender, event_grp_0_receiver) = channel();
|
||||
let event_grp_0_and_1_listener = MpscEventSenderQueue {
|
||||
id: 0,
|
||||
@ -286,10 +290,10 @@ mod tests {
|
||||
let event_man_receiver = EventReceiver {
|
||||
mpsc_receiver: manager_queue,
|
||||
};
|
||||
let mut event_man: EventManager<SendError<Event>, Event> =
|
||||
let mut event_man: EventManager<SendError<EventU32>, EventU32> =
|
||||
EventManager::new(Box::new(event_man_receiver));
|
||||
let event_0 = Event::new(Severity::INFO, 0, 5).unwrap();
|
||||
let event_1 = Event::new(Severity::HIGH, 1, 0).unwrap();
|
||||
let event_0 = EventU32::new(Severity::INFO, 0, 5).unwrap();
|
||||
let event_1 = EventU32::new(Severity::HIGH, 1, 0).unwrap();
|
||||
let (event_0_tx_0, event_0_rx_0) = channel();
|
||||
let (event_0_tx_1, event_0_rx_1) = channel();
|
||||
let event_listener_0 = MpscEventSenderQueue {
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Event support module
|
||||
|
||||
use core::hash::Hash;
|
||||
use delegate::delegate;
|
||||
use spacepackets::ecss::{EcssEnumeration, ToBeBytes};
|
||||
use spacepackets::{ByteConversionError, SizeMissmatch};
|
||||
use std::marker::PhantomData;
|
||||
@ -18,7 +19,34 @@ pub enum Severity {
|
||||
HIGH = 3,
|
||||
}
|
||||
|
||||
pub trait EventProvider: EcssEnumeration + PartialEq + Eq + Copy + Clone + Hash {
|
||||
pub trait HasSeverity {
|
||||
const SEVERITY: Severity;
|
||||
}
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct SeverityInfo {}
|
||||
impl HasSeverity for SeverityInfo {
|
||||
const SEVERITY: Severity = Severity::INFO;
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct SeverityLow {}
|
||||
impl HasSeverity for SeverityLow {
|
||||
const SEVERITY: Severity = Severity::LOW;
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct SeverityMedium {}
|
||||
impl HasSeverity for SeverityMedium {
|
||||
const SEVERITY: Severity = Severity::MEDIUM;
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct SeverityHigh {}
|
||||
impl HasSeverity for SeverityHigh {
|
||||
const SEVERITY: Severity = Severity::HIGH;
|
||||
}
|
||||
|
||||
pub trait GenericEvent: EcssEnumeration {
|
||||
type Raw;
|
||||
type GroupId;
|
||||
type UniqueId;
|
||||
@ -149,43 +177,78 @@ macro_rules! event_provider_impl {
|
||||
}
|
||||
};
|
||||
}
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Event {
|
||||
base: EventBase<u32, u16, u16>,
|
||||
}
|
||||
|
||||
impl EventProvider for Event {
|
||||
type Raw = u32;
|
||||
type GroupId = u16;
|
||||
type UniqueId = u16;
|
||||
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()
|
||||
self.raw().into()
|
||||
}
|
||||
|
||||
fn group_id_as_largest_type(&self) -> LargestGroupIdRaw {
|
||||
self.group_id()
|
||||
self.group_id().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Event {
|
||||
/// 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
|
||||
impl<SEVERITY: HasSeverity> GenericEvent for $TypedIdent<SEVERITY> {
|
||||
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, Self::Error> {
|
||||
Self::try_from_generic($severity, raw)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct EventU32 {
|
||||
base: EventBase<u32, u16, u16>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct EventU32TypedSev<SEVERITY> {
|
||||
event: EventU32,
|
||||
phantom: PhantomData<SEVERITY>,
|
||||
}
|
||||
|
||||
impl<SEVERITY: HasSeverity> From<EventU32TypedSev<SEVERITY>> for EventU32 {
|
||||
fn from(e: EventU32TypedSev<SEVERITY>) -> Self {
|
||||
Self { base: e.event.base }
|
||||
}
|
||||
}
|
||||
|
||||
impl_event_provider!(EventU32, EventU32TypedSev, u32, u16, u16);
|
||||
|
||||
impl EventU32 {
|
||||
pub fn new(
|
||||
severity: Severity,
|
||||
group_id: <Self as EventProvider>::GroupId,
|
||||
unique_id: <Self as EventProvider>::UniqueId,
|
||||
group_id: <Self as GenericEvent>::GroupId,
|
||||
unique_id: <Self as GenericEvent>::UniqueId,
|
||||
) -> Option<Self> {
|
||||
if group_id > (2u16.pow(14) - 1) {
|
||||
return None;
|
||||
@ -199,12 +262,10 @@ impl Event {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Const version of [new], but panics on invalid group ID input values.
|
||||
pub const fn const_new(
|
||||
severity: Severity,
|
||||
group_id: <Self as EventProvider>::GroupId,
|
||||
unique_id: <Self as EventProvider>::UniqueId,
|
||||
group_id: <Self as GenericEvent>::GroupId,
|
||||
unique_id: <Self as GenericEvent>::UniqueId,
|
||||
) -> Self {
|
||||
if group_id > (2u16.pow(14) - 1) {
|
||||
panic!("Group ID too large");
|
||||
@ -220,7 +281,54 @@ impl Event {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Event {
|
||||
impl<SEVERITY: HasSeverity> EventU32TypedSev<SEVERITY> {
|
||||
/// 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(
|
||||
group_id: <Self as GenericEvent>::GroupId,
|
||||
unique_id: <Self as GenericEvent>::UniqueId,
|
||||
) -> Option<Self> {
|
||||
let event = EventU32::new(SEVERITY::SEVERITY, group_id, unique_id)?;
|
||||
Some(Self {
|
||||
event,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// Const version of [new], but panics on invalid group ID input values.
|
||||
pub const fn const_new(
|
||||
group_id: <Self as GenericEvent>::GroupId,
|
||||
unique_id: <Self as GenericEvent>::UniqueId,
|
||||
) -> Self {
|
||||
let event = EventU32::const_new(SEVERITY::SEVERITY, group_id, unique_id);
|
||||
Self {
|
||||
event,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_from_generic(expected: Severity, raw: u32) -> Result<Self, Severity> {
|
||||
let severity = Severity::try_from(((raw >> 30) & 0b11) as u8).unwrap();
|
||||
if severity != expected {
|
||||
return Err(severity);
|
||||
}
|
||||
Ok(Self::const_new(
|
||||
((raw >> 16) & 0x3FFF) as u16,
|
||||
(raw & 0xFFFF) as u16,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> 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();
|
||||
@ -231,7 +339,12 @@ impl From<u32> for Event {
|
||||
}
|
||||
}
|
||||
|
||||
impl EcssEnumeration for Event {
|
||||
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);
|
||||
|
||||
impl EcssEnumeration for EventU32 {
|
||||
fn pfc(&self) -> u8 {
|
||||
32
|
||||
}
|
||||
@ -241,12 +354,26 @@ impl EcssEnumeration for Event {
|
||||
}
|
||||
}
|
||||
|
||||
//noinspection RsTraitImplementation
|
||||
impl<SEVERITY: HasSeverity> EcssEnumeration for EventU32TypedSev<SEVERITY> {
|
||||
delegate!(to self.event {
|
||||
fn pfc(&self) -> u8;
|
||||
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<(), ByteConversionError>;
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct EventSmall {
|
||||
pub struct EventU16 {
|
||||
base: EventBase<u16, u8, u8>,
|
||||
}
|
||||
|
||||
impl EventSmall {
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct EventU16TypedSev<SEVERITY> {
|
||||
event: EventU16,
|
||||
phantom: PhantomData<SEVERITY>,
|
||||
}
|
||||
|
||||
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
|
||||
///
|
||||
@ -260,8 +387,8 @@ impl EventSmall {
|
||||
/// raw event ID
|
||||
pub fn new(
|
||||
severity: Severity,
|
||||
group_id: <Self as EventProvider>::GroupId,
|
||||
unique_id: <Self as EventProvider>::UniqueId,
|
||||
group_id: <Self as GenericEvent>::GroupId,
|
||||
unique_id: <Self as GenericEvent>::UniqueId,
|
||||
) -> Option<Self> {
|
||||
if group_id > (2u8.pow(6) - 1) {
|
||||
return None;
|
||||
@ -278,8 +405,8 @@ impl EventSmall {
|
||||
|
||||
pub const fn const_new(
|
||||
severity: Severity,
|
||||
group_id: <Self as EventProvider>::GroupId,
|
||||
unique_id: <Self as EventProvider>::UniqueId,
|
||||
group_id: <Self as GenericEvent>::GroupId,
|
||||
unique_id: <Self as GenericEvent>::UniqueId,
|
||||
) -> Self {
|
||||
if group_id > (2u8.pow(6) - 1) {
|
||||
panic!("Group ID too large");
|
||||
@ -294,24 +421,55 @@ impl EventSmall {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EventProvider for EventSmall {
|
||||
type Raw = u16;
|
||||
type GroupId = u8;
|
||||
type UniqueId = u8;
|
||||
|
||||
event_provider_impl!();
|
||||
|
||||
fn raw_as_largest_type(&self) -> LargestEventRaw {
|
||||
self.raw().into()
|
||||
impl<SEVERITY: HasSeverity> EventU16TypedSev<SEVERITY> {
|
||||
/// 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(
|
||||
group_id: <Self as GenericEvent>::GroupId,
|
||||
unique_id: <Self as GenericEvent>::UniqueId,
|
||||
) -> Option<Self> {
|
||||
let event = EventU16::new(SEVERITY::SEVERITY, group_id, unique_id)?;
|
||||
Some(Self {
|
||||
event,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
fn group_id_as_largest_type(&self) -> LargestGroupIdRaw {
|
||||
self.group_id().into()
|
||||
pub const fn const_new(
|
||||
group_id: <Self as GenericEvent>::GroupId,
|
||||
unique_id: <Self as GenericEvent>::UniqueId,
|
||||
) -> Self {
|
||||
let event = EventU16::const_new(SEVERITY::SEVERITY, group_id, unique_id);
|
||||
Self {
|
||||
event,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl EcssEnumeration for EventSmall {
|
||||
fn try_from_generic(expected: Severity, raw: u16) -> Result<Self, Severity> {
|
||||
let severity = Severity::try_from(((raw >> 14) & 0b11) as u8).unwrap();
|
||||
if severity != expected {
|
||||
return Err(severity);
|
||||
}
|
||||
Ok(Self::const_new(
|
||||
((raw >> 8) & 0x3F) as u8,
|
||||
(raw & 0xFF) as u8,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl_event_provider!(EventU16, EventU16TypedSev, u16, u8, u8);
|
||||
|
||||
impl EcssEnumeration for EventU16 {
|
||||
fn pfc(&self) -> u8 {
|
||||
16
|
||||
}
|
||||
@ -321,8 +479,16 @@ impl EcssEnumeration for EventSmall {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for EventSmall {
|
||||
fn from(raw: <Self as EventProvider>::Raw) -> Self {
|
||||
//noinspection RsTraitImplementation
|
||||
impl<SEVERITY: HasSeverity> EcssEnumeration for EventU16TypedSev<SEVERITY> {
|
||||
delegate!(to self.event {
|
||||
fn pfc(&self) -> u8;
|
||||
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<(), ByteConversionError>;
|
||||
});
|
||||
}
|
||||
|
||||
impl From<u16> for EventU16 {
|
||||
fn from(raw: <Self as GenericEvent>::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;
|
||||
@ -331,10 +497,15 @@ impl From<u16> for EventSmall {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Event;
|
||||
use crate::events::{EventProvider, EventSmall, Severity};
|
||||
use super::EventU32TypedSev;
|
||||
use super::*;
|
||||
use spacepackets::ecss::EcssEnumeration;
|
||||
use spacepackets::ByteConversionError;
|
||||
use std::mem::size_of;
|
||||
@ -343,20 +514,24 @@ mod tests {
|
||||
assert_eq!(size_of::<T>(), val);
|
||||
}
|
||||
|
||||
const INFO_EVENT: Event = Event::const_new(Severity::INFO, 0, 0);
|
||||
const INFO_EVENT_SMALL: EventSmall = EventSmall::const_new(Severity::INFO, 0, 0);
|
||||
const HIGH_SEV_EVENT: Event = Event::const_new(Severity::HIGH, 0x3FFF, 0xFFFF);
|
||||
const HIGH_SEV_EVENT_SMALL: EventSmall = EventSmall::const_new(Severity::HIGH, 0x3F, 0xff);
|
||||
const INFO_EVENT: EventU32TypedSev<SeverityInfo> = EventU32TypedSev::const_new(0, 0);
|
||||
const INFO_EVENT_SMALL: EventU16TypedSev<SeverityInfo> = EventU16TypedSev::const_new(0, 0);
|
||||
const HIGH_SEV_EVENT: EventU32TypedSev<SeverityHigh> =
|
||||
EventU32TypedSev::const_new(0x3FFF, 0xFFFF);
|
||||
const HIGH_SEV_EVENT_SMALL: EventU16TypedSev<SeverityHigh> =
|
||||
EventU16TypedSev::const_new(0x3F, 0xff);
|
||||
|
||||
#[test]
|
||||
fn test_normal_from_raw_conversion() {
|
||||
let conv_from_raw = Event::from(INFO_EVENT.raw());
|
||||
let conv_from_raw = EventU32TypedSev::<SeverityInfo>::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 = EventSmall::from(INFO_EVENT_SMALL.raw());
|
||||
let conv_from_raw = EventU16TypedSev::<SeverityInfo>::try_from(INFO_EVENT_SMALL.raw())
|
||||
.expect("Creating typed EventU16 failed");
|
||||
assert_eq!(conv_from_raw, INFO_EVENT_SMALL);
|
||||
}
|
||||
|
||||
@ -408,18 +583,18 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn invalid_group_id_normal() {
|
||||
assert!(Event::new(Severity::MEDIUM, 2_u16.pow(14), 0).is_none());
|
||||
assert!(EventU32TypedSev::<SeverityMedium>::new(2_u16.pow(14), 0).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_group_id_small() {
|
||||
assert!(EventSmall::new(Severity::MEDIUM, 2_u8.pow(6), 0).is_none());
|
||||
assert!(EventU16TypedSev::<SeverityMedium>::new(2_u8.pow(6), 0).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regular_new() {
|
||||
assert_eq!(
|
||||
Event::new(Severity::INFO, 0, 0).expect("Creating regular event failed"),
|
||||
EventU32TypedSev::<SeverityInfo>::new(0, 0).expect("Creating regular event failed"),
|
||||
INFO_EVENT
|
||||
);
|
||||
}
|
||||
@ -427,7 +602,7 @@ mod tests {
|
||||
#[test]
|
||||
fn small_new() {
|
||||
assert_eq!(
|
||||
EventSmall::new(Severity::INFO, 0, 0).expect("Creating regular event failed"),
|
||||
EventU16TypedSev::<SeverityInfo>::new(0, 0).expect("Creating regular event failed"),
|
||||
INFO_EVENT_SMALL
|
||||
);
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ mod allocvec {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::events::{Event, Severity};
|
||||
use crate::events::{EventU32, Severity};
|
||||
use crate::pus::tests::CommonTmInfo;
|
||||
use spacepackets::ByteConversionError;
|
||||
use std::collections::VecDeque;
|
||||
@ -270,7 +270,7 @@ mod tests {
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
struct TmInfo {
|
||||
pub common: CommonTmInfo,
|
||||
pub event: Event,
|
||||
pub event: EventU32,
|
||||
pub aux_data: Vec<u8>,
|
||||
}
|
||||
|
||||
@ -284,9 +284,7 @@ mod tests {
|
||||
assert!(tm.source_data().is_some());
|
||||
let src_data = tm.source_data().unwrap();
|
||||
assert!(src_data.len() >= 4);
|
||||
let event = Event::try_from(u32::from_be_bytes(src_data[0..4].try_into().unwrap()));
|
||||
assert!(event.is_ok());
|
||||
let event = event.unwrap();
|
||||
let event = EventU32::from(u32::from_be_bytes(src_data[0..4].try_into().unwrap()));
|
||||
let mut aux_data = Vec::new();
|
||||
if src_data.len() > 4 {
|
||||
aux_data.extend_from_slice(&src_data[4..]);
|
||||
@ -313,7 +311,7 @@ mod tests {
|
||||
reporter: &mut EventReporter,
|
||||
sender: &mut TestSender,
|
||||
time_stamp: &[u8],
|
||||
event: Event,
|
||||
event: EventU32,
|
||||
severity: Severity,
|
||||
aux_data: Option<&[u8]>,
|
||||
) {
|
||||
@ -355,7 +353,7 @@ mod tests {
|
||||
if let Some(err_data) = error_data {
|
||||
error_copy.extend_from_slice(err_data);
|
||||
}
|
||||
let event = Event::new(severity, EXAMPLE_GROUP_ID, EXAMPLE_EVENT_ID_0)
|
||||
let event = EventU32::new(severity, EXAMPLE_GROUP_ID, EXAMPLE_EVENT_ID_0)
|
||||
.expect("Error creating example event");
|
||||
report_basic_event(
|
||||
&mut reporter,
|
||||
@ -418,7 +416,7 @@ mod tests {
|
||||
expected_found_len: usize,
|
||||
) {
|
||||
let time_stamp_empty: [u8; 7] = [0; 7];
|
||||
let event = Event::new(Severity::INFO, EXAMPLE_GROUP_ID, EXAMPLE_EVENT_ID_0)
|
||||
let event = EventU32::new(Severity::INFO, EXAMPLE_GROUP_ID, EXAMPLE_EVENT_ID_0)
|
||||
.expect("Error creating example event");
|
||||
let err = reporter.event_info(sender, &time_stamp_empty, event, None);
|
||||
assert!(err.is_err());
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::events::EventProvider;
|
||||
use crate::events::{EventU16TypedSev, EventU32TypedSev, GenericEvent, HasSeverity, Severity};
|
||||
use alloc::boxed::Box;
|
||||
use core::hash::Hash;
|
||||
use hashbrown::HashSet;
|
||||
|
||||
use crate::pus::event::EventReporter;
|
||||
@ -17,7 +18,7 @@ pub use heapless_mod::*;
|
||||
/// structure to track disabled events. A more primitive and embedded friendly
|
||||
/// solution could track this information in a static or pre-allocated list which contains
|
||||
/// the disabled events.
|
||||
pub trait PusEventMgmtBackendProvider<Provider: EventProvider> {
|
||||
pub trait PusEventMgmtBackendProvider<Provider: GenericEvent> {
|
||||
type Error;
|
||||
|
||||
fn event_enabled(&self, event: &Provider) -> bool;
|
||||
@ -31,12 +32,12 @@ pub trait PusEventMgmtBackendProvider<Provider: EventProvider> {
|
||||
/// This provider is a good option for host systems or larger embedded systems where
|
||||
/// the expected occasional memory allocation performed by the [HashSet] is not an issue.
|
||||
#[derive(Default)]
|
||||
pub struct DefaultPusMgmtBackendProvider<Provider: EventProvider> {
|
||||
pub struct DefaultPusMgmtBackendProvider<Provider: GenericEvent> {
|
||||
disabled: HashSet<Provider>,
|
||||
}
|
||||
|
||||
impl<Provider: EventProvider> PusEventMgmtBackendProvider<Provider>
|
||||
for DefaultPusMgmtBackendProvider<Provider>
|
||||
impl<Provider: GenericEvent + PartialEq + Eq + Hash + Copy + Clone>
|
||||
PusEventMgmtBackendProvider<Provider> for DefaultPusMgmtBackendProvider<Provider>
|
||||
{
|
||||
type Error = ();
|
||||
fn event_enabled(&self, event: &Provider) -> bool {
|
||||
@ -55,18 +56,18 @@ impl<Provider: EventProvider> PusEventMgmtBackendProvider<Provider>
|
||||
#[cfg(feature = "heapless")]
|
||||
pub mod heapless_mod {
|
||||
use super::*;
|
||||
use crate::events::{EventProvider, LargestEventRaw};
|
||||
use crate::events::{GenericEvent, LargestEventRaw};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// TODO: After a new version of heapless is released which uses hash32 version 0.3, try using
|
||||
// regular Event type again.
|
||||
#[derive(Default)]
|
||||
pub struct HeaplessPusMgmtBckendProvider<const N: usize, Provider: EventProvider> {
|
||||
pub struct HeaplessPusMgmtBckendProvider<const N: usize, Provider: GenericEvent> {
|
||||
disabled: heapless::FnvIndexSet<LargestEventRaw, N>,
|
||||
phantom: PhantomData<Provider>,
|
||||
}
|
||||
|
||||
impl<const N: usize, Provider: EventProvider> PusEventMgmtBackendProvider<Provider>
|
||||
impl<const N: usize, Provider: GenericEvent> PusEventMgmtBackendProvider<Provider>
|
||||
for HeaplessPusMgmtBckendProvider<N, Provider>
|
||||
{
|
||||
type Error = ();
|
||||
@ -87,24 +88,76 @@ pub mod heapless_mod {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PusEventManager<BackendError, Provider: EventProvider> {
|
||||
pub struct PusEventManager<BackendError, Provider: GenericEvent> {
|
||||
reporter: EventReporter,
|
||||
backend: Box<dyn PusEventMgmtBackendProvider<Provider, Error = BackendError>>,
|
||||
}
|
||||
|
||||
impl<BackendError, Provider: EventProvider> PusEventManager<BackendError, Provider> {
|
||||
pub fn handle_event<E>(
|
||||
impl<BackendError, Event: GenericEvent> PusEventManager<BackendError, Event> {
|
||||
pub fn enable_tm_for_event(&mut self, event: &Event) -> Result<bool, BackendError> {
|
||||
self.backend.enable_event_reporting(event)
|
||||
}
|
||||
|
||||
pub fn disable_tm_for_event(&mut self, event: &Event) -> Result<bool, BackendError> {
|
||||
self.backend.disable_event_reporting(event)
|
||||
}
|
||||
|
||||
pub fn generate_pus_event_tm_generic<E>(
|
||||
&mut self,
|
||||
severity: Severity,
|
||||
sender: &mut (impl EcssTmSender<E> + ?Sized),
|
||||
time_stamp: &[u8],
|
||||
event: Provider,
|
||||
event: Event,
|
||||
aux_data: Option<&[u8]>,
|
||||
) -> Result<bool, EcssTmError<E>> {
|
||||
if !self.backend.event_enabled(&event) {
|
||||
return Ok(false);
|
||||
}
|
||||
self.reporter
|
||||
match severity {
|
||||
Severity::INFO => self
|
||||
.reporter
|
||||
.event_info(sender, time_stamp, event, aux_data)
|
||||
.map(|_| true)
|
||||
.map(|_| true),
|
||||
Severity::LOW => self
|
||||
.reporter
|
||||
.event_low_severity(sender, time_stamp, event, aux_data)
|
||||
.map(|_| true),
|
||||
Severity::MEDIUM => self
|
||||
.reporter
|
||||
.event_medium_severity(sender, time_stamp, event, aux_data)
|
||||
.map(|_| true),
|
||||
Severity::HIGH => self
|
||||
.reporter
|
||||
.event_high_severity(sender, time_stamp, event, aux_data)
|
||||
.map(|_| true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<BackendError, SEVERITY: HasSeverity>
|
||||
PusEventManager<BackendError, EventU32TypedSev<SEVERITY>>
|
||||
{
|
||||
pub fn generate_pus_event_tm<E>(
|
||||
&mut self,
|
||||
sender: &mut (impl EcssTmSender<E> + ?Sized),
|
||||
time_stamp: &[u8],
|
||||
event: EventU32TypedSev<SEVERITY>,
|
||||
aux_data: Option<&[u8]>,
|
||||
) -> Result<bool, EcssTmError<E>> {
|
||||
self.generate_pus_event_tm_generic(SEVERITY::SEVERITY, sender, time_stamp, event, aux_data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<BackendError, SEVERITY: HasSeverity>
|
||||
PusEventManager<BackendError, EventU16TypedSev<SEVERITY>>
|
||||
{
|
||||
pub fn generate_pus_event_tm<E>(
|
||||
&mut self,
|
||||
sender: &mut (impl EcssTmSender<E> + ?Sized),
|
||||
time_stamp: &[u8],
|
||||
event: EventU16TypedSev<SEVERITY>,
|
||||
aux_data: Option<&[u8]>,
|
||||
) -> Result<bool, EcssTmError<E>> {
|
||||
self.generate_pus_event_tm_generic(SEVERITY::SEVERITY, sender, time_stamp, event, aux_data)
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,26 @@
|
||||
#![allow(dead_code, unused_imports)]
|
||||
use fsrc_core::events::{Event, EventProvider, LargestEventRaw, LargestGroupIdRaw, Severity};
|
||||
use fsrc_core::events::{
|
||||
EventU32TypedSev, GenericEvent, HasSeverity, LargestEventRaw, LargestGroupIdRaw, Severity,
|
||||
SeverityInfo, SeverityLow, SeverityMedium,
|
||||
};
|
||||
|
||||
struct GroupIdIntrospection {
|
||||
name: &'static str,
|
||||
id: LargestGroupIdRaw,
|
||||
}
|
||||
|
||||
struct EventIntrospection {
|
||||
struct EventIntrospection<SEVERITY: HasSeverity + 'static> {
|
||||
name: &'static str,
|
||||
group_id: GroupIdIntrospection,
|
||||
event: &'static Event,
|
||||
event: &'static EventU32TypedSev<SEVERITY>,
|
||||
info: &'static str,
|
||||
}
|
||||
|
||||
//#[event(descr="This is some info event")]
|
||||
const INFO_EVENT_0: Event = Event::const_new(Severity::INFO, 0, 0);
|
||||
const INFO_EVENT_0: EventU32TypedSev<SeverityInfo> = EventU32TypedSev::const_new(0, 0);
|
||||
|
||||
// This is ideally auto-generated
|
||||
const INFO_EVENT_0_INTROSPECTION: EventIntrospection = EventIntrospection {
|
||||
const INFO_EVENT_0_INTROSPECTION: EventIntrospection<SeverityInfo> = EventIntrospection {
|
||||
name: "INFO_EVENT_0",
|
||||
group_id: GroupIdIntrospection {
|
||||
id: 0,
|
||||
@ -28,9 +31,9 @@ const INFO_EVENT_0_INTROSPECTION: EventIntrospection = EventIntrospection {
|
||||
};
|
||||
|
||||
//#[event(descr="This is some low severity event")]
|
||||
const SOME_LOW_SEV_EVENT: Event = Event::const_new(Severity::LOW, 0, 12);
|
||||
const SOME_LOW_SEV_EVENT: EventU32TypedSev<SeverityLow> = EventU32TypedSev::const_new(0, 12);
|
||||
|
||||
const EVENT_LIST: [&'static Event; 2] = [&INFO_EVENT_0, &SOME_LOW_SEV_EVENT];
|
||||
//const EVENT_LIST: [&'static Event; 2] = [&INFO_EVENT_0, &SOME_LOW_SEV_EVENT];
|
||||
|
||||
//#[event_group]
|
||||
const TEST_GROUP_NAME: u16 = 1;
|
||||
@ -38,11 +41,12 @@ const TEST_GROUP_NAME: u16 = 1;
|
||||
const TEST_GROUP_NAME_NAME: &'static str = "TEST_GROUP_NAME";
|
||||
|
||||
//#[event(desc="Some medium severity event")]
|
||||
const MEDIUM_SEV_EVENT_IN_OTHER_GROUP: Event =
|
||||
Event::const_new(Severity::MEDIUM, TEST_GROUP_NAME, 0);
|
||||
const MEDIUM_SEV_EVENT_IN_OTHER_GROUP: EventU32TypedSev<SeverityMedium> =
|
||||
EventU32TypedSev::const_new(TEST_GROUP_NAME, 0);
|
||||
|
||||
// Also auto-generated
|
||||
const MEDIUM_SEV_EVENT_IN_OTHER_GROUP_INTROSPECTION: EventIntrospection = EventIntrospection {
|
||||
const MEDIUM_SEV_EVENT_IN_OTHER_GROUP_INTROSPECTION: EventIntrospection<SeverityMedium> =
|
||||
EventIntrospection {
|
||||
name: "MEDIUM_SEV_EVENT_IN_OTHER_GROUP",
|
||||
group_id: GroupIdIntrospection {
|
||||
name: TEST_GROUP_NAME_NAME,
|
||||
@ -54,10 +58,10 @@ const MEDIUM_SEV_EVENT_IN_OTHER_GROUP_INTROSPECTION: EventIntrospection = EventI
|
||||
|
||||
#[test]
|
||||
fn main() {
|
||||
let test = stringify!(INFO_EVENT);
|
||||
println!("{:?}", test);
|
||||
for event in EVENT_LIST {
|
||||
println!("{:?}", event);
|
||||
}
|
||||
//let test = stringify!(INFO_EVENT);
|
||||
//println!("{:?}", test);
|
||||
//for event in EVENT_LIST {
|
||||
// println!("{:?}", event);
|
||||
//}
|
||||
//let test_struct =
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user