basic test framework done
This commit is contained in:
parent
cc1f3ed091
commit
74f65243e4
@ -35,7 +35,7 @@ use alloc::vec::Vec;
|
|||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use stdmod::MpscEventReceiver;
|
pub use stdmod::*;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
|
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
|
||||||
enum ListenerType {
|
enum ListenerType {
|
||||||
@ -96,6 +96,14 @@ pub struct EventManager<SendProviderError, Event: GenericEvent = EventU32, AuxDa
|
|||||||
event_receiver: Box<dyn EventReceiver<Event, AuxDataProvider>>,
|
event_receiver: Box<dyn EventReceiver<Event, AuxDataProvider>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Safety: It is safe to implement [Send] because all fields in the [EventManager] are [Send]
|
||||||
|
/// as well
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
unsafe impl<E, Event: GenericEvent + Send, AuxDataProvider: Send> Send
|
||||||
|
for EventManager<E, Event, AuxDataProvider>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
pub enum HandlerResult<Provider: GenericEvent, AuxDataProvider> {
|
pub enum HandlerResult<Provider: GenericEvent, AuxDataProvider> {
|
||||||
Empty,
|
Empty,
|
||||||
Handled(u32, Provider, Option<AuxDataProvider>),
|
Handled(u32, Provider, Option<AuxDataProvider>),
|
||||||
@ -128,8 +136,11 @@ impl<E, Event: GenericEvent + Copy> EventManager<E, Event> {
|
|||||||
///
|
///
|
||||||
/// For example, this can be useful for a handler component which sends every event as
|
/// For example, this can be useful for a handler component which sends every event as
|
||||||
/// a telemetry packet.
|
/// a telemetry packet.
|
||||||
pub fn subscribe_all(&mut self, dest: impl SendEventProvider<Event, Error = E> + 'static) {
|
pub fn subscribe_all(
|
||||||
self.update_listeners(ListenerType::All, dest);
|
&mut self,
|
||||||
|
send_provider: impl SendEventProvider<Event, Error = E> + 'static,
|
||||||
|
) {
|
||||||
|
self.update_listeners(ListenerType::All, send_provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function which removes single subscriptions for which a group subscription already
|
/// Helper function which removes single subscriptions for which a group subscription already
|
||||||
@ -226,23 +237,24 @@ impl<E, Event: GenericEvent + Copy, AuxDataProvider: Clone>
|
|||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub mod stdmod {
|
pub mod stdmod {
|
||||||
|
use super::*;
|
||||||
use crate::event_man::{EventReceiver, EventWithAuxData};
|
use crate::event_man::{EventReceiver, EventWithAuxData};
|
||||||
use crate::events::{EventU16, EventU32, GenericEvent};
|
use crate::events::{EventU16, EventU32, GenericEvent};
|
||||||
use crate::util::Params;
|
use crate::util::Params;
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::{Receiver, SendError, Sender};
|
||||||
|
|
||||||
pub struct MpscEventReceiver<Event: GenericEvent = EventU32> {
|
pub struct MpscEventReceiver<Event: GenericEvent + Send = EventU32> {
|
||||||
mpsc_receiver: Receiver<(Event, Option<Params>)>,
|
mpsc_receiver: Receiver<(Event, Option<Params>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Event: GenericEvent> MpscEventReceiver<Event> {
|
impl<Event: GenericEvent + Send> MpscEventReceiver<Event> {
|
||||||
pub fn new(receiver: Receiver<(Event, Option<Params>)>) -> Self {
|
pub fn new(receiver: Receiver<(Event, Option<Params>)>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
mpsc_receiver: receiver,
|
mpsc_receiver: receiver,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<Event: GenericEvent> EventReceiver<Event> for MpscEventReceiver<Event> {
|
impl<Event: GenericEvent + Send> EventReceiver<Event> for MpscEventReceiver<Event> {
|
||||||
fn receive(&mut self) -> Option<EventWithAuxData<Event>> {
|
fn receive(&mut self) -> Option<EventWithAuxData<Event>> {
|
||||||
if let Ok(event_and_data) = self.mpsc_receiver.try_recv() {
|
if let Ok(event_and_data) = self.mpsc_receiver.try_recv() {
|
||||||
return Some(event_and_data);
|
return Some(event_and_data);
|
||||||
@ -253,6 +265,35 @@ pub mod stdmod {
|
|||||||
|
|
||||||
pub type MpscEventU32Receiver = MpscEventReceiver<EventU32>;
|
pub type MpscEventU32Receiver = MpscEventReceiver<EventU32>;
|
||||||
pub type MpscEventU16Receiver = MpscEventReceiver<EventU16>;
|
pub type MpscEventU16Receiver = MpscEventReceiver<EventU16>;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct MpscEventSendProvider<Event: GenericEvent + Send> {
|
||||||
|
id: u32,
|
||||||
|
sender: Sender<(Event, Option<Params>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Safety: Send is safe to implement because both the ID and the MPSC sender are Send
|
||||||
|
//unsafe impl<Event: GenericEvent> Send for MpscEventSendProvider<Event> {}
|
||||||
|
|
||||||
|
impl<Event: GenericEvent + Send> MpscEventSendProvider<Event> {
|
||||||
|
pub fn new(id: u32, sender: Sender<(Event, Option<Params>)>) -> Self {
|
||||||
|
Self { id, sender }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Event: GenericEvent + Send> SendEventProvider<Event> for MpscEventSendProvider<Event> {
|
||||||
|
type Error = SendError<(Event, Option<Params>)>;
|
||||||
|
|
||||||
|
fn id(&self) -> u32 {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
fn send(&mut self, event: Event, aux_data: Option<Params>) -> Result<(), Self::Error> {
|
||||||
|
self.sender.send((event, aux_data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type MpscEventU32SendProvider = MpscEventSendProvider<EventU32>;
|
||||||
|
pub type MpscEventU16SendProvider = MpscEventSendProvider<EventU16>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -38,6 +38,9 @@ pub struct DefaultPusMgmtBackendProvider<Event: GenericEvent = EventU32> {
|
|||||||
disabled: HashSet<Event>,
|
disabled: HashSet<Event>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Safety: All contained field are [Send] as well
|
||||||
|
unsafe impl<Event: GenericEvent + Send> Send for DefaultPusMgmtBackendProvider<Event> {}
|
||||||
|
|
||||||
impl<Event: GenericEvent> Default for DefaultPusMgmtBackendProvider<Event> {
|
impl<Event: GenericEvent> Default for DefaultPusMgmtBackendProvider<Event> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -73,13 +76,19 @@ pub mod heapless_mod {
|
|||||||
// TODO: After a new version of heapless is released which uses hash32 version 0.3, try using
|
// TODO: After a new version of heapless is released which uses hash32 version 0.3, try using
|
||||||
// regular Event type again.
|
// regular Event type again.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct HeaplessPusMgmtBckendProvider<const N: usize, Provider: GenericEvent> {
|
pub struct HeaplessPusMgmtBackendProvider<const N: usize, Provider: GenericEvent> {
|
||||||
disabled: heapless::FnvIndexSet<LargestEventRaw, N>,
|
disabled: heapless::FnvIndexSet<LargestEventRaw, N>,
|
||||||
phantom: PhantomData<Provider>,
|
phantom: PhantomData<Provider>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Safety: All contained field are [Send] as well
|
||||||
|
unsafe impl<const N: usize, Event: GenericEvent + Send> Send
|
||||||
|
for HeaplessPusMgmtBackendProvider<N, Event>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
impl<const N: usize, Provider: GenericEvent> PusEventMgmtBackendProvider<Provider>
|
impl<const N: usize, Provider: GenericEvent> PusEventMgmtBackendProvider<Provider>
|
||||||
for HeaplessPusMgmtBckendProvider<N, Provider>
|
for HeaplessPusMgmtBackendProvider<N, Provider>
|
||||||
{
|
{
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
@ -116,6 +125,9 @@ pub struct PusEventTmManager<BackendError, Provider: GenericEvent> {
|
|||||||
backend: Box<dyn PusEventMgmtBackendProvider<Provider, Error = BackendError>>,
|
backend: Box<dyn PusEventMgmtBackendProvider<Provider, Error = BackendError>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Safety: All contained fields are send as well.
|
||||||
|
unsafe impl<E: Send, Event: GenericEvent + Send> Send for PusEventTmManager<E, Event> {}
|
||||||
|
|
||||||
impl<BackendError, Provider: GenericEvent> PusEventTmManager<BackendError, Provider> {
|
impl<BackendError, Provider: GenericEvent> PusEventTmManager<BackendError, Provider> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
reporter: EventReporter,
|
reporter: EventReporter,
|
||||||
@ -136,7 +148,6 @@ impl<BackendError, Event: GenericEvent> PusEventTmManager<BackendError, Event> {
|
|||||||
|
|
||||||
pub fn generate_pus_event_tm_generic<E>(
|
pub fn generate_pus_event_tm_generic<E>(
|
||||||
&mut self,
|
&mut self,
|
||||||
severity: Severity,
|
|
||||||
sender: &mut (impl EcssTmSender<Error = E> + ?Sized),
|
sender: &mut (impl EcssTmSender<Error = E> + ?Sized),
|
||||||
time_stamp: &[u8],
|
time_stamp: &[u8],
|
||||||
event: Event,
|
event: Event,
|
||||||
@ -145,10 +156,7 @@ impl<BackendError, Event: GenericEvent> PusEventTmManager<BackendError, Event> {
|
|||||||
if !self.backend.event_enabled(&event) {
|
if !self.backend.event_enabled(&event) {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
if event.severity() != severity {
|
match event.severity() {
|
||||||
return Err(EventManError::SeverityMissmatch(severity, event.severity()));
|
|
||||||
}
|
|
||||||
match severity {
|
|
||||||
Severity::INFO => self
|
Severity::INFO => self
|
||||||
.reporter
|
.reporter
|
||||||
.event_info(sender, time_stamp, event, aux_data)
|
.event_info(sender, time_stamp, event, aux_data)
|
||||||
@ -195,13 +203,7 @@ impl<BackendError> PusEventTmManager<BackendError, EventU32> {
|
|||||||
event: EventU32TypedSev<Severity>,
|
event: EventU32TypedSev<Severity>,
|
||||||
aux_data: Option<&[u8]>,
|
aux_data: Option<&[u8]>,
|
||||||
) -> Result<bool, EventManError<E>> {
|
) -> Result<bool, EventManError<E>> {
|
||||||
self.generate_pus_event_tm_generic(
|
self.generate_pus_event_tm_generic(sender, time_stamp, event.into(), aux_data)
|
||||||
Severity::SEVERITY,
|
|
||||||
sender,
|
|
||||||
time_stamp,
|
|
||||||
event.into(),
|
|
||||||
aux_data,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,13 +263,7 @@ mod tests {
|
|||||||
assert!(res.is_ok());
|
assert!(res.is_ok());
|
||||||
assert!(res.unwrap());
|
assert!(res.unwrap());
|
||||||
let mut event_sent = event_man
|
let mut event_sent = event_man
|
||||||
.generate_pus_event_tm_generic(
|
.generate_pus_event_tm_generic(&mut sender, &EMPTY_STAMP, LOW_SEV_EVENT, None)
|
||||||
Severity::LOW,
|
|
||||||
&mut sender,
|
|
||||||
&EMPTY_STAMP,
|
|
||||||
LOW_SEV_EVENT,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.expect("Sending low severity event failed");
|
.expect("Sending low severity event failed");
|
||||||
assert!(!event_sent);
|
assert!(!event_sent);
|
||||||
let res = event_rx.try_recv();
|
let res = event_rx.try_recv();
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
|
use fsrc_core::event_man::{EventManager, MpscEventReceiver, MpscEventU32SendProvider};
|
||||||
use fsrc_core::events::{EventU32, EventU32TypedSev, Severity, SeverityInfo};
|
use fsrc_core::events::{EventU32, EventU32TypedSev, Severity, SeverityInfo};
|
||||||
use fsrc_core::pus::event_man::{DefaultPusMgmtBackendProvider, EventReporter, PusEventTmManager};
|
use fsrc_core::pus::event_man::{DefaultPusMgmtBackendProvider, EventReporter, PusEventTmManager};
|
||||||
use fsrc_core::pus::{EcssTmError, EcssTmSender};
|
use fsrc_core::pus::{EcssTmError, EcssTmSender};
|
||||||
|
use fsrc_core::util::Params;
|
||||||
use spacepackets::tm::PusTm;
|
use spacepackets::tm::PusTm;
|
||||||
use std::sync::mpsc::{channel, SendError, TryRecvError};
|
use std::sync::mpsc::{channel, SendError, TryRecvError};
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
const INFO_EVENT: EventU32TypedSev<SeverityInfo> =
|
const INFO_EVENT: EventU32TypedSev<SeverityInfo> =
|
||||||
EventU32TypedSev::<SeverityInfo>::const_new(1, 0);
|
EventU32TypedSev::<SeverityInfo>::const_new(1, 0);
|
||||||
@ -24,27 +27,87 @@ impl EcssTmSender for EventTmSender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_basic() {
|
fn test_threaded_usage() {
|
||||||
let reporter = EventReporter::new(0x02, 128).expect("Creating event repoter failed");
|
let (event_sender, event_man_receiver) = channel();
|
||||||
let backend = DefaultPusMgmtBackendProvider::<EventU32>::default();
|
let event_receiver = MpscEventReceiver::new(event_man_receiver);
|
||||||
let mut event_man = PusEventTmManager::new(reporter, Box::new(backend));
|
let mut event_man = EventManager::new(Box::new(event_receiver));
|
||||||
let (event_tx, event_rx) = channel();
|
|
||||||
let mut sender = EventTmSender { sender: event_tx };
|
|
||||||
let mut event_sent = event_man
|
|
||||||
.generate_pus_event_tm(&mut sender, &EMPTY_STAMP, INFO_EVENT, None)
|
|
||||||
.expect("Sending info event failed");
|
|
||||||
|
|
||||||
assert!(event_sent);
|
let (pus_event_man_tx, pus_event_man_rx) = channel();
|
||||||
// Will not check packet here, correctness of packet was tested somewhere else
|
let pus_event_man_send_provider = MpscEventU32SendProvider::new(1, pus_event_man_tx);
|
||||||
event_rx.recv().expect("Receiving event TM failed");
|
event_man.subscribe_all(pus_event_man_send_provider);
|
||||||
let res = event_man.disable_tm_for_event_with_sev(&INFO_EVENT);
|
let (event_tx, event_rx) = channel();
|
||||||
|
let reporter = EventReporter::new(0x02, 128).expect("Creating event reporter failed");
|
||||||
|
let backend = DefaultPusMgmtBackendProvider::<EventU32>::default();
|
||||||
|
let mut pus_event_man = PusEventTmManager::new(reporter, Box::new(backend));
|
||||||
|
// PUS + Generic event manager thread
|
||||||
|
let jh0 = thread::spawn(move || {
|
||||||
|
let mut sender = EventTmSender { sender: event_tx };
|
||||||
|
loop {
|
||||||
|
let res = event_man.try_event_handling();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
match pus_event_man_rx.try_recv() {
|
||||||
|
Ok((event, aux_data)) => {
|
||||||
|
// TODO: Convert auxiliary data into raw byte format
|
||||||
|
if let Some(aux_data) = aux_data {
|
||||||
|
match aux_data {
|
||||||
|
Params::Heapless(_) => {}
|
||||||
|
Params::Vec(_) => {}
|
||||||
|
Params::String(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let res = pus_event_man.generate_pus_event_tm_generic(
|
||||||
|
&mut sender,
|
||||||
|
&EMPTY_STAMP,
|
||||||
|
event,
|
||||||
|
None,
|
||||||
|
);
|
||||||
assert!(res.is_ok());
|
assert!(res.is_ok());
|
||||||
assert!(res.unwrap());
|
assert!(res.unwrap());
|
||||||
event_sent = event_man
|
break;
|
||||||
.generate_pus_event_tm(&mut sender, &EMPTY_STAMP, INFO_EVENT, None)
|
}
|
||||||
|
Err(e) => {
|
||||||
|
if let TryRecvError::Disconnected = e {
|
||||||
|
panic!("Event receiver disconnected!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Event sender and TM checker thread
|
||||||
|
let jh1 = thread::spawn(move || {
|
||||||
|
event_sender
|
||||||
|
.send((INFO_EVENT.into(), None))
|
||||||
.expect("Sending info event failed");
|
.expect("Sending info event failed");
|
||||||
assert!(!event_sent);
|
loop {
|
||||||
let res = event_rx.try_recv();
|
match event_rx.try_recv() {
|
||||||
assert!(res.is_err());
|
// Event TM received successfully
|
||||||
assert!(matches!(res.unwrap_err(), TryRecvError::Empty));
|
Ok(_) => break,
|
||||||
|
Err(e) => {
|
||||||
|
if let TryRecvError::Disconnected = e {
|
||||||
|
panic!("Event sender disconnected!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event_sender
|
||||||
|
.send((
|
||||||
|
LOW_SEV_EVENT.into(),
|
||||||
|
Some(Params::Heapless((2_u32, 3_u32).into())),
|
||||||
|
))
|
||||||
|
.expect("Sending low severity event failed");
|
||||||
|
loop {
|
||||||
|
match event_rx.try_recv() {
|
||||||
|
// Event TM received successfully
|
||||||
|
Ok(_) => break,
|
||||||
|
Err(e) => {
|
||||||
|
if let TryRecvError::Disconnected = e {
|
||||||
|
panic!("Event sender disconnected!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
jh0.join().expect("Joining manager thread failed");
|
||||||
|
jh1.join().expect("Joining creator thread failed");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user