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="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="buildTarget" value="REMOTE" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<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"
|
||||
dependencies = [
|
||||
"atomic-option",
|
||||
"crossbeam-channel 0.4.4",
|
||||
"crossbeam-channel",
|
||||
"num_cpus",
|
||||
"parking_lot_core",
|
||||
]
|
||||
@ -38,12 +38,6 @@ version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
@ -59,20 +53,10 @@ version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.7.2",
|
||||
"crossbeam-utils",
|
||||
"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]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
@ -80,17 +64,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if 0.1.10",
|
||||
"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",
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
@ -108,7 +82,7 @@ name = "launchpad"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bus",
|
||||
"crossbeam-channel 0.5.4",
|
||||
"num",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@ -130,6 +104,82 @@ version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.1"
|
||||
@ -146,7 +196,7 @@ version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"cfg-if",
|
||||
"cloudabi",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
|
@ -8,4 +8,4 @@ edition = "2021"
|
||||
[dependencies]
|
||||
thiserror = "1.0"
|
||||
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 executable;
|
||||
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 {
|
||||
pub event_id: u32,
|
||||
use num::pow;
|
||||
|
||||
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
|
||||
/// * `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
|
||||
pub fn exec_sched_multi<
|
||||
T: Executable<Error = E> + Send + 'static + ?Sized,
|
||||
|
@ -8,6 +8,8 @@ pub struct ObjectId {
|
||||
name: &'static str,
|
||||
}
|
||||
|
||||
/// Each object which is stored inside the [object manager][ObjectManager] needs to implemented
|
||||
/// this trait
|
||||
pub trait SystemObject {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn get_object_id(&self) -> &ObjectId;
|
||||
@ -16,7 +18,21 @@ pub trait SystemObject {
|
||||
|
||||
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 {
|
||||
obj_map: HashMap<ObjectId, Box<dyn ManagedSystemObject>>,
|
||||
}
|
||||
@ -53,6 +69,8 @@ impl ObjectManager {
|
||||
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> {
|
||||
self.obj_map
|
||||
.get(key)
|
||||
|
0
src/core/pool.rs
Normal file
0
src/core/pool.rs
Normal file
@ -1,3 +1,3 @@
|
||||
fn main() {
|
||||
println!("hello");
|
||||
println!("Hello World")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user