Merge pull request 'Init Event Module' (#4) from events into main
Reviewed-on: rust/launchpad#4
This commit is contained in:
commit
9119357b7e
18
.idea/runConfigurations/Clippy_Fix.xml
Normal file
18
.idea/runConfigurations/Clippy_Fix.xml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Clippy Fix" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||||
|
<option name="command" value="clippy --fix" />
|
||||||
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
|
<option name="channel" value="DEFAULT" />
|
||||||
|
<option name="requiredFeatures" value="true" />
|
||||||
|
<option name="allFeatures" value="false" />
|
||||||
|
<option name="emulateTerminal" value="false" />
|
||||||
|
<option name="withSudo" value="false" />
|
||||||
|
<option name="backtrace" value="SHORT" />
|
||||||
|
<envs />
|
||||||
|
<option name="isRedirectInput" value="false" />
|
||||||
|
<option name="redirectInputPath" value="" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
@ -7,7 +7,6 @@
|
|||||||
<option name="allFeatures" value="false" />
|
<option name="allFeatures" value="false" />
|
||||||
<option name="emulateTerminal" value="false" />
|
<option name="emulateTerminal" value="false" />
|
||||||
<option name="withSudo" value="false" />
|
<option name="withSudo" value="false" />
|
||||||
<option name="buildTarget" value="REMOTE" />
|
|
||||||
<option name="backtrace" value="SHORT" />
|
<option name="backtrace" value="SHORT" />
|
||||||
<envs />
|
<envs />
|
||||||
<option name="isRedirectInput" value="false" />
|
<option name="isRedirectInput" value="false" />
|
||||||
|
112
Cargo.lock
generated
112
Cargo.lock
generated
@ -27,7 +27,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "f1e66e1779f5b1440f1a58220ba3b3ded4427175f0a9fb8d7066521f8b4e8f2b"
|
checksum = "f1e66e1779f5b1440f1a58220ba3b3ded4427175f0a9fb8d7066521f8b4e8f2b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-option",
|
"atomic-option",
|
||||||
"crossbeam-channel 0.4.4",
|
"crossbeam-channel",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"parking_lot_core",
|
"parking_lot_core",
|
||||||
]
|
]
|
||||||
@ -38,12 +38,6 @@ version = "0.1.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cloudabi"
|
name = "cloudabi"
|
||||||
version = "0.0.3"
|
version = "0.0.3"
|
||||||
@ -59,20 +53,10 @@ version = "0.4.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
|
checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-utils 0.7.2",
|
"crossbeam-utils",
|
||||||
"maybe-uninit",
|
"maybe-uninit",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-channel"
|
|
||||||
version = "0.5.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if 1.0.0",
|
|
||||||
"crossbeam-utils 0.8.8",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.7.2"
|
version = "0.7.2"
|
||||||
@ -80,17 +64,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"cfg-if 0.1.10",
|
"cfg-if",
|
||||||
"lazy_static",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-utils"
|
|
||||||
version = "0.8.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if 1.0.0",
|
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -108,7 +82,7 @@ name = "launchpad"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bus",
|
"bus",
|
||||||
"crossbeam-channel 0.5.4",
|
"num",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -130,6 +104,82 @@ version = "2.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97fbc387afefefd5e9e39493299f3069e14a140dd34dc19b4c1c1a8fddb6a790"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.13.1"
|
version = "1.13.1"
|
||||||
@ -146,7 +196,7 @@ version = "0.7.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"
|
checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if",
|
||||||
"cloudabi",
|
"cloudabi",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
|
@ -8,4 +8,4 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
bus = "2.2.3"
|
bus = "2.2.3"
|
||||||
crossbeam-channel = "0.5.4"
|
num = "0.4"
|
||||||
|
10
src/core.rs
10
src/core.rs
@ -1,3 +1,13 @@
|
|||||||
|
//! # Core components of the Flight Software Rust Crate (FSRC) collection.
|
||||||
|
//!
|
||||||
|
//! This includes components to perform the following tasks
|
||||||
|
//!
|
||||||
|
//! 1. Object Management with the [objects] module
|
||||||
|
//! 2. Task schedule with the [executable] module
|
||||||
|
//! 3. Events with the [events] module and event management with the [event_man] module
|
||||||
|
//! 4. Pre-Allocated memory pools with the [pool] module
|
||||||
|
pub mod event_man;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod executable;
|
pub mod executable;
|
||||||
pub mod objects;
|
pub mod objects;
|
||||||
|
pub mod pool;
|
||||||
|
310
src/core/event_man.rs
Normal file
310
src/core/event_man.rs
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
use crate::core::events::{Event, EventRaw, GroupId};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
|
||||||
|
enum ListenerType {
|
||||||
|
Single(EventRaw),
|
||||||
|
Group(GroupId),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait EventListener {
|
||||||
|
type Error;
|
||||||
|
|
||||||
|
fn id(&self) -> u32;
|
||||||
|
fn send_to(&mut self, event: Event) -> Result<(), Self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Listener<E> {
|
||||||
|
ltype: ListenerType,
|
||||||
|
dest: Box<dyn EventListener<Error = E>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ReceivesAllEvent {
|
||||||
|
fn receive(&mut self) -> Option<Event>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EventManager<E> {
|
||||||
|
listeners: HashMap<ListenerType, Vec<Listener<E>>>,
|
||||||
|
event_receiver: Box<dyn ReceivesAllEvent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum HandlerResult {
|
||||||
|
Empty,
|
||||||
|
Handled(u32, Event),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> EventManager<E> {
|
||||||
|
pub fn new(event_receiver: Box<dyn ReceivesAllEvent>) -> Self {
|
||||||
|
EventManager {
|
||||||
|
listeners: HashMap::new(),
|
||||||
|
event_receiver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn subscribe_single(
|
||||||
|
&mut self,
|
||||||
|
event: Event,
|
||||||
|
dest: impl EventListener<Error = E> + 'static,
|
||||||
|
) {
|
||||||
|
self.update_listeners(ListenerType::Single(event.raw()), dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subscribe_group(
|
||||||
|
&mut self,
|
||||||
|
group_id: GroupId,
|
||||||
|
dest: impl EventListener<Error = E> + 'static,
|
||||||
|
) {
|
||||||
|
self.update_listeners(ListenerType::Group(group_id), dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_listeners(
|
||||||
|
&mut self,
|
||||||
|
key: ListenerType,
|
||||||
|
dest: impl EventListener<Error = E> + 'static,
|
||||||
|
) {
|
||||||
|
if let std::collections::hash_map::Entry::Vacant(e) = self.listeners.entry(key) {
|
||||||
|
e.insert(vec![Listener {
|
||||||
|
ltype: key,
|
||||||
|
dest: Box::new(dest),
|
||||||
|
}]);
|
||||||
|
} else {
|
||||||
|
let vec = self.listeners.get_mut(&key).unwrap();
|
||||||
|
// To prevent double insertions
|
||||||
|
for entry in vec.iter() {
|
||||||
|
if entry.ltype == key && entry.dest.id() == dest.id() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vec.push(Listener {
|
||||||
|
ltype: key,
|
||||||
|
dest: Box::new(dest),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_event_handling(&mut self) -> Result<HandlerResult, E> {
|
||||||
|
let mut err_status = None;
|
||||||
|
let mut num_recipients = 0;
|
||||||
|
let mut send_handler = |event, llist: &mut Vec<Listener<E>>| {
|
||||||
|
for listener in llist.iter_mut() {
|
||||||
|
if let Err(e) = listener.dest.send_to(event) {
|
||||||
|
err_status = Some(Err(e));
|
||||||
|
} else {
|
||||||
|
num_recipients += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(event) = self.event_receiver.receive() {
|
||||||
|
let single_key = ListenerType::Single(event.raw());
|
||||||
|
if self.listeners.contains_key(&single_key) {
|
||||||
|
send_handler(event, self.listeners.get_mut(&single_key).unwrap());
|
||||||
|
}
|
||||||
|
let group_key = ListenerType::Group(event.group_id());
|
||||||
|
if self.listeners.contains_key(&group_key) {
|
||||||
|
send_handler(event, self.listeners.get_mut(&group_key).unwrap());
|
||||||
|
}
|
||||||
|
if let Some(err) = err_status {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return Ok(HandlerResult::Handled(num_recipients, event));
|
||||||
|
}
|
||||||
|
Ok(HandlerResult::Empty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{EventListener, HandlerResult, ReceivesAllEvent};
|
||||||
|
use crate::core::event_man::EventManager;
|
||||||
|
use crate::core::events::{Event, Severity};
|
||||||
|
use std::sync::mpsc::{channel, Receiver, SendError, Sender};
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
struct EventReceiver {
|
||||||
|
mpsc_receiver: Receiver<Event>,
|
||||||
|
}
|
||||||
|
impl ReceivesAllEvent for EventReceiver {
|
||||||
|
fn receive(&mut self) -> Option<Event> {
|
||||||
|
self.mpsc_receiver.try_recv().ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct MpscEventSenderQueue {
|
||||||
|
id: u32,
|
||||||
|
mpsc_sender: Sender<Event>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventListener for MpscEventSenderQueue {
|
||||||
|
type Error = SendError<Event>;
|
||||||
|
|
||||||
|
fn id(&self) -> u32 {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
fn send_to(&mut self, event: Event) -> Result<(), Self::Error> {
|
||||||
|
self.mpsc_sender.send(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_next_event(expected: Event, receiver: &Receiver<Event>) {
|
||||||
|
for _ in 0..5 {
|
||||||
|
if let Ok(event) = receiver.try_recv() {
|
||||||
|
assert_eq!(event, expected);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
thread::sleep(Duration::from_millis(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_handled_event(res: HandlerResult, expected: Event, expected_num_sent: u32) {
|
||||||
|
assert!(matches!(res, HandlerResult::Handled { .. }));
|
||||||
|
if let HandlerResult::Handled(num_recipients, event) = res {
|
||||||
|
assert_eq!(event, expected);
|
||||||
|
assert_eq!(num_recipients, expected_num_sent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_basic() {
|
||||||
|
let (event_sender, manager_queue) = channel();
|
||||||
|
let event_man_receiver = EventReceiver {
|
||||||
|
mpsc_receiver: manager_queue,
|
||||||
|
};
|
||||||
|
let mut event_man: EventManager<SendError<Event>> =
|
||||||
|
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 (single_event_sender, single_event_receiver) = channel();
|
||||||
|
let single_event_listener = MpscEventSenderQueue {
|
||||||
|
id: 0,
|
||||||
|
mpsc_sender: single_event_sender,
|
||||||
|
};
|
||||||
|
event_man.subscribe_single(event_grp_0, single_event_listener);
|
||||||
|
let (group_event_sender_0, group_event_receiver_0) = channel();
|
||||||
|
let group_event_listener = MpscEventSenderQueue {
|
||||||
|
id: 1,
|
||||||
|
mpsc_sender: group_event_sender_0,
|
||||||
|
};
|
||||||
|
event_man.subscribe_group(event_grp_1_0.group_id(), group_event_listener);
|
||||||
|
|
||||||
|
// Test event with one listener
|
||||||
|
event_sender
|
||||||
|
.send(event_grp_0)
|
||||||
|
.expect("Sending single error failed");
|
||||||
|
let res = event_man.try_event_handling();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
check_handled_event(res.unwrap(), event_grp_0, 1);
|
||||||
|
check_next_event(event_grp_0, &single_event_receiver);
|
||||||
|
|
||||||
|
// Test event which is sent to all group listeners
|
||||||
|
event_sender
|
||||||
|
.send(event_grp_1_0)
|
||||||
|
.expect("Sending group error failed");
|
||||||
|
let res = event_man.try_event_handling();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
check_handled_event(res.unwrap(), event_grp_1_0, 1);
|
||||||
|
check_next_event(event_grp_1_0, &group_event_receiver_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test listening for multiple groups
|
||||||
|
#[test]
|
||||||
|
fn test_multi_group() {
|
||||||
|
let (event_sender, manager_queue) = channel();
|
||||||
|
let event_man_receiver = EventReceiver {
|
||||||
|
mpsc_receiver: manager_queue,
|
||||||
|
};
|
||||||
|
let mut event_man: EventManager<SendError<Event>> =
|
||||||
|
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_sender, event_grp_0_receiver) = channel();
|
||||||
|
let event_grp_0_and_1_listener = MpscEventSenderQueue {
|
||||||
|
id: 0,
|
||||||
|
mpsc_sender: event_grp_0_sender,
|
||||||
|
};
|
||||||
|
event_man.subscribe_group(event_grp_0.group_id(), event_grp_0_and_1_listener.clone());
|
||||||
|
event_man.subscribe_group(event_grp_1_0.group_id(), event_grp_0_and_1_listener);
|
||||||
|
|
||||||
|
event_sender
|
||||||
|
.send(event_grp_0)
|
||||||
|
.expect("Sending Event Group 0 failed");
|
||||||
|
event_sender
|
||||||
|
.send(event_grp_1_0)
|
||||||
|
.expect("Sendign Event Group 1 failed");
|
||||||
|
let res = event_man.try_event_handling();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
check_handled_event(res.unwrap(), event_grp_0, 1);
|
||||||
|
let res = event_man.try_event_handling();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
check_handled_event(res.unwrap(), event_grp_1_0, 1);
|
||||||
|
|
||||||
|
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 (event_sender, manager_queue) = channel();
|
||||||
|
let event_man_receiver = EventReceiver {
|
||||||
|
mpsc_receiver: manager_queue,
|
||||||
|
};
|
||||||
|
let mut event_man: EventManager<SendError<Event>> =
|
||||||
|
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_tx_0, event_0_rx_0) = channel();
|
||||||
|
let (event_0_tx_1, event_0_rx_1) = channel();
|
||||||
|
let event_listener_0 = MpscEventSenderQueue {
|
||||||
|
id: 0,
|
||||||
|
mpsc_sender: event_0_tx_0,
|
||||||
|
};
|
||||||
|
let event_listener_1 = MpscEventSenderQueue {
|
||||||
|
id: 1,
|
||||||
|
mpsc_sender: event_0_tx_1,
|
||||||
|
};
|
||||||
|
event_man.subscribe_single(event_0, event_listener_0.clone());
|
||||||
|
event_man.subscribe_single(event_0, event_listener_1);
|
||||||
|
event_sender
|
||||||
|
.send(event_0)
|
||||||
|
.expect("Triggering Event 0 failed");
|
||||||
|
let res = event_man.try_event_handling();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
check_handled_event(res.unwrap(), event_0, 2);
|
||||||
|
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.clone());
|
||||||
|
event_sender
|
||||||
|
.send(event_0)
|
||||||
|
.expect("Triggering Event 0 failed");
|
||||||
|
event_sender
|
||||||
|
.send(event_1)
|
||||||
|
.expect("Triggering Event 1 failed");
|
||||||
|
|
||||||
|
// 3 Events messages will be sent now
|
||||||
|
let res = event_man.try_event_handling();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
check_handled_event(res.unwrap(), event_0, 2);
|
||||||
|
let res = event_man.try_event_handling();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
check_handled_event(res.unwrap(), event_1, 1);
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Double insertion should be detected, result should remain the same
|
||||||
|
event_man.subscribe_group(event_1.group_id(), event_listener_0);
|
||||||
|
event_sender
|
||||||
|
.send(event_1)
|
||||||
|
.expect("Triggering Event 1 failed");
|
||||||
|
let res = event_man.try_event_handling();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
check_handled_event(res.unwrap(), event_1, 1);
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,132 @@
|
|||||||
pub struct Event {
|
use num::pow;
|
||||||
pub event_id: u32,
|
|
||||||
|
pub type GroupId = u16;
|
||||||
|
pub type UniqueId = u16;
|
||||||
|
pub type EventRaw = u32;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
|
pub enum Severity {
|
||||||
|
INFO = 1,
|
||||||
|
LOW = 2,
|
||||||
|
MEDIUM = 3,
|
||||||
|
HIGH = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for Severity {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
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)]
|
||||||
|
pub struct Event {
|
||||||
|
severity: Severity,
|
||||||
|
group_id: GroupId,
|
||||||
|
unique_id: UniqueId,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 3 bits of the raw event ID
|
||||||
|
/// `group_id`: Related events can be grouped using a group ID. The group ID will occupy the
|
||||||
|
/// next 13 bits after the severity. Therefore, the size is limited by dec 8191 hex 0x1FFF.
|
||||||
|
/// `unique_id`: Each event has a unique 16 bit ID occupying the last 16 bits of the
|
||||||
|
/// raw event ID
|
||||||
|
pub fn new(severity: Severity, group_id: GroupId, unique_id: UniqueId) -> Option<Event> {
|
||||||
|
if group_id > (pow::pow(2u8 as u16, 13) - 1) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(Event {
|
||||||
|
severity,
|
||||||
|
group_id,
|
||||||
|
unique_id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the severity of an event. Returns None if that severity bit field of the raw event
|
||||||
|
/// ID is invalid
|
||||||
|
pub fn severity(&self) -> Severity {
|
||||||
|
self.severity
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn group_id(&self) -> GroupId {
|
||||||
|
self.group_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unique_id(&self) -> UniqueId {
|
||||||
|
self.unique_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn raw(&self) -> EventRaw {
|
||||||
|
(((self.severity as u32) << 29) as u32
|
||||||
|
| ((self.group_id as u32) << 16) as u32
|
||||||
|
| self.unique_id as u32) as EventRaw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<EventRaw> for Event {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(raw: u32) -> Result<Self, Self::Error> {
|
||||||
|
let severity: Option<Severity> = (((raw >> 29) & 0b111) as u8).try_into().ok();
|
||||||
|
if severity.is_none() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
let group_id = ((raw >> 16) & 0x1FFF) as u16;
|
||||||
|
let unique_id = (raw & 0xFFFF) as u16;
|
||||||
|
Event::new(severity.unwrap(), group_id, unique_id).ok_or(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::Event;
|
||||||
|
use crate::core::events::Severity;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_events() {
|
||||||
|
let event = Event::new(Severity::INFO, 0, 0).unwrap();
|
||||||
|
assert_eq!(event.severity(), Severity::INFO);
|
||||||
|
assert_eq!(event.unique_id(), 0);
|
||||||
|
assert_eq!(event.group_id(), 0);
|
||||||
|
|
||||||
|
let raw_event = event.raw();
|
||||||
|
assert_eq!(raw_event, 0x20000000);
|
||||||
|
let conv_from_raw = Event::try_from(raw_event);
|
||||||
|
assert!(conv_from_raw.is_ok());
|
||||||
|
let opt_event = conv_from_raw.ok();
|
||||||
|
assert!(opt_event.is_some());
|
||||||
|
let event = opt_event.unwrap();
|
||||||
|
assert_eq!(event.severity(), Severity::INFO);
|
||||||
|
assert_eq!(event.unique_id(), 0);
|
||||||
|
assert_eq!(event.group_id(), 0);
|
||||||
|
|
||||||
|
let event = Event::new(Severity::HIGH, 0x1FFF, 0xFFFF).unwrap();
|
||||||
|
assert_eq!(event.severity(), Severity::HIGH);
|
||||||
|
assert_eq!(event.group_id(), 0x1FFF);
|
||||||
|
assert_eq!(event.unique_id(), 0xFFFF);
|
||||||
|
let raw_event = event.raw();
|
||||||
|
assert_eq!(raw_event, 0x9FFFFFFF);
|
||||||
|
let conv_from_raw = Event::try_from(raw_event);
|
||||||
|
assert!(conv_from_raw.is_ok());
|
||||||
|
let opt_event = conv_from_raw.ok();
|
||||||
|
assert!(opt_event.is_some());
|
||||||
|
let event = opt_event.unwrap();
|
||||||
|
assert_eq!(event.severity(), Severity::HIGH);
|
||||||
|
assert_eq!(event.group_id(), 0x1FFF);
|
||||||
|
assert_eq!(event.unique_id(), 0xFFFF);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ pub fn exec_sched_single<
|
|||||||
///
|
///
|
||||||
/// * `executable_vec`: Vector of executable objects
|
/// * `executable_vec`: Vector of executable objects
|
||||||
/// * `task_freq`: Optional frequency of task. Required for periodic and fixed cycle tasks
|
/// * `task_freq`: Optional frequency of task. Required for periodic and fixed cycle tasks
|
||||||
/// * `op_code`: Operation code which is passed to the executable task periodic_op call
|
/// * `op_code`: Operation code which is passed to the executable task [operation call][Executable::periodic_op]
|
||||||
/// * `termination`: Optional termination handler which can cancel threads with a broadcast
|
/// * `termination`: Optional termination handler which can cancel threads with a broadcast
|
||||||
pub fn exec_sched_multi<
|
pub fn exec_sched_multi<
|
||||||
T: Executable<Error = E> + Send + 'static + ?Sized,
|
T: Executable<Error = E> + Send + 'static + ?Sized,
|
||||||
|
@ -8,6 +8,8 @@ pub struct ObjectId {
|
|||||||
name: &'static str,
|
name: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Each object which is stored inside the [object manager][ObjectManager] needs to implemented
|
||||||
|
/// this trait
|
||||||
pub trait SystemObject {
|
pub trait SystemObject {
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
fn get_object_id(&self) -> &ObjectId;
|
fn get_object_id(&self) -> &ObjectId;
|
||||||
@ -16,7 +18,21 @@ pub trait SystemObject {
|
|||||||
|
|
||||||
pub trait ManagedSystemObject: SystemObject + Any {}
|
pub trait ManagedSystemObject: SystemObject + Any {}
|
||||||
|
|
||||||
/// Helper module to manage multiple SystemObject by mapping them using an ObjectId
|
/// Helper module to manage multiple [ManagedSystemObjects][ManagedSystemObject] by mapping them
|
||||||
|
/// using an [object ID][ObjectId]
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```rs
|
||||||
|
/// let mut obj_manager = ObjectManager::default();
|
||||||
|
/// let expl_obj_id = ObjectId {
|
||||||
|
/// id: 0,
|
||||||
|
/// name: "Example 0",
|
||||||
|
/// };
|
||||||
|
/// let example_obj = ExampleSysObj::new(expl_obj_id, 42);
|
||||||
|
/// obj_manager.insert(Box::new(example_obj))
|
||||||
|
/// let obj_back_casted: Option<&ExampleSysObj> = obj_manager.get(&expl_obj_id);
|
||||||
|
/// let expl_obj_back_casted = obj_back_casted.unwrap();
|
||||||
|
/// ```
|
||||||
pub struct ObjectManager {
|
pub struct ObjectManager {
|
||||||
obj_map: HashMap<ObjectId, Box<dyn ManagedSystemObject>>,
|
obj_map: HashMap<ObjectId, Box<dyn ManagedSystemObject>>,
|
||||||
}
|
}
|
||||||
@ -53,6 +69,8 @@ impl ObjectManager {
|
|||||||
Ok(init_success)
|
Ok(init_success)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve an object stored inside the manager. The type to retrieve needs to be explicitly
|
||||||
|
/// passed as a generic parameter
|
||||||
pub fn get<T: Any>(&self, key: &ObjectId) -> Option<&T> {
|
pub fn get<T: Any>(&self, key: &ObjectId) -> Option<&T> {
|
||||||
self.obj_map
|
self.obj_map
|
||||||
.get(key)
|
.get(key)
|
||||||
|
0
src/core/pool.rs
Normal file
0
src/core/pool.rs
Normal file
@ -1,3 +1,3 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
println!("hello");
|
println!("Hello World")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user