This commit is contained in:
2025-04-02 22:50:55 -05:00
parent e645bbcc08
commit bfe3333d65
5 changed files with 451 additions and 36 deletions
+56
View File
@@ -0,0 +1,56 @@
# Real-time Framework for Embedded systems (RFE)
RFE is a framework for building real-time embedded applications in Rust. It provides a message-passing architecture for inter-application communication, time management, and scheduling at different rates.
## Features
- Message-passing architecture for inter-application communication
- Time management for both system and monotonic time
- Scheduling of applications at different rates (1Hz to 100Hz)
- Support for different platforms through feature flags
- Connectors for communication between instances (TCP, UDP, Memory)
## Usage
To use RFE, you need to create an RfeInstance, add applications to it, and then run it at 100Hz. Applications must implement the App trait.
```rust
use rfe::*;
struct MyApp;
impl App for MyApp {
fn init(&mut self, rfe: &mut Rfe) -> anyhow::Result<()> {
// Initialize the application
Ok(())
}
fn run(&mut self, rfe: &mut Rfe) {
// Run the application
}
fn hk(&mut self, rfe: &mut Rfe) {
// Generate housekeeping data
}
fn out_data(&mut self, rfe: &mut Rfe) {
// Generate output data
}
fn get_app_rate(&self) -> Rate {
Rate::Hz10 // Run at 10Hz
}
}
```
## Platform Support
RFE supports multiple platforms through feature flags:
- `std`: Standard library support (Unix, Windows)
- `rp2040`: Raspberry Pi Pico support
- `reflect`: Runtime type information for debugging
## License
This project is licensed under the MIT License - see the LICENSE file for details.
+24
View File
@@ -1,11 +1,35 @@
/*!
* Connector module for RFE
*
* This module provides the Connector trait and implementations for various
* communication methods between RFE instances, including:
* - Memory connectors for inter-process communication
* - TCP connectors for network communication
* - UDP connectors for network communication
*/
use core::fmt::Debug; use core::fmt::Debug;
use crate::msg::MsgPacket; use crate::msg::MsgPacket;
extern crate alloc; extern crate alloc;
use alloc::vec::Vec; use alloc::vec::Vec;
/// Connector trait for inter-instance communication
///
/// This trait defines the interface for connectors that enable communication
/// between RFE instances. Connectors are responsible for sending and receiving
/// messages between instances.
pub trait Connector: Debug { pub trait Connector: Debug {
/// Send messages to another instance
///
/// # Arguments
/// * `msgs` - The messages to send
fn send(&mut self, msgs: Vec<MsgPacket>); fn send(&mut self, msgs: Vec<MsgPacket>);
/// Receive messages from another instance
///
/// # Returns
/// * `Some(Vec<MsgPacket>)` - If messages are available
/// * `None` - If no messages are available
fn recv(&mut self) -> Option<Vec<MsgPacket>>; fn recv(&mut self) -> Option<Vec<MsgPacket>>;
} }
+75
View File
@@ -1,25 +1,100 @@
#![no_std] #![no_std]
/*!
* Real-time Framework for Embedded systems (RFE)
*
* RFE is a framework for building real-time embedded applications in Rust.
* It provides a message-passing architecture for inter-application communication,
* time management, and scheduling at different rates.
*
* # Features
*
* - Message-passing architecture for inter-application communication
* - Time management for both system and monotonic time
* - Scheduling of applications at different rates (1Hz to 100Hz)
* - Support for different platforms through feature flags
* - Connectors for communication between instances (TCP, UDP, Memory)
*
* # Usage
*
* To use RFE, you need to create an RfeInstance, add applications to it,
* and then run it at 100Hz. Applications must implement the App trait.
*
* ```rust
* use rfe::*;
*
* struct MyApp;
*
* impl App for MyApp {
* fn init(&mut self, rfe: &mut Rfe) -> anyhow::Result<()> {
* // Initialize the application
* Ok(())
* }
*
* fn run(&mut self, rfe: &mut Rfe) {
* // Run the application
* }
*
* fn hk(&mut self, rfe: &mut Rfe) {
* // Generate housekeeping data
* }
*
* fn out_data(&mut self, rfe: &mut Rfe) {
* // Generate output data
* }
*
* fn get_app_rate(&self) -> Rate {
* Rate::Hz10 // Run at 10Hz
* }
* }
* ```
*/
#[cfg(feature = "std")] #[cfg(feature = "std")]
extern crate std; extern crate std;
/// Connector module for inter-instance communication
pub mod connector; pub mod connector;
use bincode::config::Configuration; use bincode::config::Configuration;
/// Message module for defining message types
pub mod msg; pub mod msg;
/// Core RFE implementation
mod rfe; mod rfe;
pub use rfe::*; pub use rfe::*;
/// Reflection module for runtime type information
#[cfg(feature = "reflect")] #[cfg(feature = "reflect")]
pub mod reflect; pub mod reflect;
/// Macros for RFE
pub use macros; pub use macros;
/// Serial communication module
pub mod serial; pub mod serial;
/// Time management module
pub mod time; pub mod time;
/// Utility functions and types
pub mod utils; pub mod utils;
/// Bincode configuration for serialization
pub const BINCODE_CONFIG: Configuration = bincode::config::standard(); pub const BINCODE_CONFIG: Configuration = bincode::config::standard();
/// Macro for unwrapping a Result and printing an error message if it fails
///
/// # Arguments
/// * `$x` - The Result to unwrap
/// * `$msg` - The error message to print if the Result is an Err
///
/// # Example
/// ```rust
/// use rfe::unwrap_print_err;
/// use log::error;
///
/// fn main() {
/// let result: Result<(), &str> = Err("error");
/// unwrap_print_err!(result, "Failed to do something");
/// }
/// ```
#[macro_export] #[macro_export]
macro_rules! unwrap_print_err { macro_rules! unwrap_print_err {
($x:expr, $msg: tt) => { ($x:expr, $msg: tt) => {
+252 -34
View File
@@ -1,3 +1,12 @@
/*!
* Real-time Framework for Embedded systems (RFE)
*
* This module provides the core functionality for the RFE framework:
* - Application scheduling at different rates (1Hz to 100Hz)
* - Message passing between applications
* - Time management for both system and monotonic time
* - Connector management for inter-instance communication
*/
extern crate alloc; extern crate alloc;
use core::cell::RefCell; use core::cell::RefCell;
@@ -13,99 +22,207 @@ use crate::{
time::{TimeData, TimeDriver}, time::{TimeData, TimeDriver},
}; };
/// Housekeeping data trait
///
/// This trait is used to mark types that can be used as housekeeping data.
/// Housekeeping data is used to monitor the health and status of applications.
pub trait Hk: Sized + Clone + Copy + 'static + Send + Sync {} pub trait Hk: Sized + Clone + Copy + 'static + Send + Sync {}
/// Blanket implementation for all types that meet the requirements
impl<T> Hk for T where T: Sized + Clone + Copy + 'static + Send + Sync {} impl<T> Hk for T where T: Sized + Clone + Copy + 'static + Send + Sync {}
/// Output data trait
///
/// This trait is used to mark types that can be used as output data.
/// Output data is the primary data produced by applications.
pub trait OutData: Sized + Clone + Copy + 'static + Send + Sync {} pub trait OutData: Sized + Clone + Copy + 'static + Send + Sync {}
/// Blanket implementation for all types that meet the requirements
impl<T> OutData for T where T: Sized + Clone + Copy + 'static + Send + Sync {} impl<T> OutData for T where T: Sized + Clone + Copy + 'static + Send + Sync {}
/// Application execution rates
///
/// This enum defines the rates at which applications can be scheduled.
/// The RFE framework runs at 100Hz, and applications can be scheduled
/// at various rates derived from this base rate.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Rate { pub enum Rate {
/// 1Hz (once per second)
Hz1, Hz1,
/// 5Hz (5 times per second)
Hz5, Hz5,
/// 10Hz (10 times per second)
Hz10, Hz10,
/// 20Hz (20 times per second)
Hz20, Hz20,
/// 50Hz (50 times per second)
Hz50, Hz50,
/// 100Hz (100 times per second, every tick)
Hz100, Hz100,
} }
/// Reference to an RfeTime instance
///
/// This type alias is used to share a single time reference between multiple RFE instances.
type RfeTimeRef<'a> = Rc<RefCell<RfeTime<'a>>>; type RfeTimeRef<'a> = Rc<RefCell<RfeTime<'a>>>;
/// Time management for RFE
///
/// This struct manages time for the RFE framework, providing both system time
/// and monotonic time through a TimeDriver implementation.
pub struct RfeTime<'a> { pub struct RfeTime<'a> {
/// Time data including scheduler counter and time offset
time_data: TimeData, time_data: TimeData,
/// Driver for time operations
time_driver: &'a dyn TimeDriver, time_driver: &'a dyn TimeDriver,
} }
/// Main RFE instance
///
/// This struct represents a single RFE instance, which can contain multiple applications
/// and connectors. It manages the scheduling of applications and the routing of messages.
pub struct RfeInstance<'a> { pub struct RfeInstance<'a> {
/// List of applications registered with this instance
app_list: HashMap<&'a str, AppRef<'a>>, app_list: HashMap<&'a str, AppRef<'a>>,
/// Reference to the time management
time: RfeTimeRef<'a>, time: RfeTimeRef<'a>,
/// The instance identifier
#[allow(dead_code)] #[allow(dead_code)]
instance: Instance, instance: Instance,
/// List of connectors for inter-instance communication
connectors: Vec<ConnectorState<'a>>, connectors: Vec<ConnectorState<'a>>,
/// Scheduler counter, incremented on each tick
sch_counter: u64, sch_counter: u64,
} }
/// Reference to an application
///
/// This struct holds a reference to an application and its associated RFE instance.
/// It also stores the rates at which the application should be run.
pub struct AppRef<'a> { pub struct AppRef<'a> {
/// Reference to the application
app: &'a mut dyn App, app: &'a mut dyn App,
/// Rate at which the application's run method should be called
app_rate: Rate, app_rate: Rate,
/// Rate at which the application's out_data method should be called
out_data_rate: Rate, out_data_rate: Rate,
/// Rate at which the application's hk method should be called
hk_rate: Rate, hk_rate: Rate,
/// RFE instance for this application
rfe: Rfe<'a>, rfe: Rfe<'a>,
} }
/// Core RFE interface for applications
///
/// This struct provides the interface for applications to interact with the RFE framework.
/// It handles message subscription, sending, and receiving, as well as time management.
pub struct Rfe<'a> { pub struct Rfe<'a> {
/// Messages this application is subscribed to
subscriptions: HashSet<TargetMsg>, subscriptions: HashSet<TargetMsg>,
/// Messages to be sent to other applications or connectors
msgs_to_send: Vec<MsgPacket>, msgs_to_send: Vec<MsgPacket>,
msgs_recevied: VecDeque<MsgPacket>, /// Messages received from other applications or connectors
msgs_received: VecDeque<MsgPacket>,
/// The instance this RFE belongs to
instance: Instance, instance: Instance,
/// Reference to the time management
time: RfeTimeRef<'a>, time: RfeTimeRef<'a>,
/// Flag indicating if subscriptions have been updated
subs_updated: bool, subs_updated: bool,
} }
/// State of a connector
///
/// This struct holds a reference to a connector and its associated state.
/// It tracks subscriptions and subscription request timing.
#[derive(Debug)] #[derive(Debug)]
pub struct ConnectorState<'a> { pub struct ConnectorState<'a> {
/// Reference to the connector
connector: &'a mut dyn Connector, connector: &'a mut dyn Connector,
/// Messages this connector is subscribed to
subscriptions: HashSet<TargetMsg>, subscriptions: HashSet<TargetMsg>,
/// Flag indicating if subscriptions have been received
subs_received: bool, subs_received: bool,
/// Scheduler counter value when subscriptions were last requested
subs_last_requested: u64, subs_last_requested: u64,
} }
impl<'a> Rfe<'a> { impl<'a> Rfe<'a> {
/// Creates a new RFE instance
///
/// # Arguments
/// * `instance` - The instance this RFE belongs to
/// * `time` - Reference to the time management
pub fn new(instance: Instance, time: RfeTimeRef<'a>) -> Self { pub fn new(instance: Instance, time: RfeTimeRef<'a>) -> Self {
Self { Self {
subscriptions: HashSet::new(), subscriptions: HashSet::new(),
msgs_to_send: Vec::new(), msgs_to_send: Vec::new(),
msgs_recevied: VecDeque::new(), msgs_received: VecDeque::new(),
instance, instance,
subs_updated: false, subs_updated: false,
time, time,
} }
} }
/// Returns the instance this RFE belongs to
pub fn get_instance(&self) -> Instance { pub fn get_instance(&self) -> Instance {
return self.instance; self.instance
} }
/// Subscribe to a message
///
/// This method subscribes the application to a specific message type.
/// The application will receive messages of this type from other applications
/// and connectors.
///
/// # Arguments
/// * `msg` - The message type to subscribe to
pub fn subscribe(&mut self, msg: TargetMsg) { pub fn subscribe(&mut self, msg: TargetMsg) {
self.subscriptions.insert(msg); self.subscriptions.insert(msg);
self.subs_updated = true; self.subs_updated = true;
} }
/// Subscribe to multiple messages
///
/// This method subscribes the application to multiple message types.
/// The application will receive messages of these types from other applications
/// and connectors.
///
/// # Arguments
/// * `msgs` - The message types to subscribe to
pub fn subscribe_all<T: IntoIterator<Item = TargetMsg>>(&mut self, msgs: T) { pub fn subscribe_all<T: IntoIterator<Item = TargetMsg>>(&mut self, msgs: T) {
self.subscriptions.extend(msgs.into_iter()); self.subscriptions.extend(msgs.into_iter());
self.subs_updated = true; self.subs_updated = true;
} }
/// Unsubscribe from a message
///
/// This method unsubscribes the application from a specific message type.
/// The application will no longer receive messages of this type.
///
/// # Arguments
/// * `msg` - The message type to unsubscribe from
pub fn unsubscribe(&mut self, msg: &TargetMsg) { pub fn unsubscribe(&mut self, msg: &TargetMsg) {
self.subscriptions.remove(msg); self.subscriptions.remove(msg);
self.subs_updated = true; self.subs_updated = true;
} }
/// Unsubscribe from all messages
///
/// This method unsubscribes the application from all message types.
/// The application will no longer receive any messages.
pub fn unsubscribe_all(&mut self) { pub fn unsubscribe_all(&mut self) {
self.subscriptions.clear(); self.subscriptions.clear();
self.subs_updated = true; self.subs_updated = true;
} }
/// Send a message
///
/// This method sends a message from this application to other applications
/// and connectors that are subscribed to this message type.
///
/// # Arguments
/// * `msg` - The message to send
pub fn send(&mut self, msg: Msg) { pub fn send(&mut self, msg: Msg) {
self.msgs_to_send.push(MsgPacket::new( self.msgs_to_send.push(MsgPacket::new(
self.get_instance(), self.get_instance(),
@@ -114,41 +231,110 @@ impl<'a> Rfe<'a> {
)); ));
} }
/// Send a command to a specific instance
///
/// This method sends a command to a specific instance.
/// The command will be received by applications in that instance
/// that are subscribed to this message type.
///
/// # Arguments
/// * `msg` - The command to send
/// * `target` - The target instance to send the command to
pub fn send_cmd(&mut self, msg: Msg, target: Instance) { pub fn send_cmd(&mut self, msg: Msg, target: Instance) {
self.msgs_to_send self.msgs_to_send
.push(MsgPacket::new(target, msg, self.get_system_time())); .push(MsgPacket::new(target, msg, self.get_system_time()));
} }
/// Posts a message to this RFE's receive queue
///
/// # Arguments
/// * `msg` - The message to post
pub fn post_message(&mut self, msg: MsgPacket) { pub fn post_message(&mut self, msg: MsgPacket) {
self.msgs_recevied.push_back(msg); self.msgs_received.push_back(msg);
} }
/// Receives a message from this RFE's receive queue
///
/// # Returns
/// * `Some(MsgPacket)` - If a message is available
/// * `None` - If no message is available
pub fn recv(&mut self) -> Option<MsgPacket> { pub fn recv(&mut self) -> Option<MsgPacket> {
self.msgs_recevied.pop_front() self.msgs_received.pop_front()
} }
/// time starting from power on or program start /// Get mission elapsed time
///
/// This method returns the time in microseconds since power on or program start.
/// It is useful for measuring durations and scheduling events.
///
/// # Returns
/// * Time in microseconds since power on or program start
pub fn get_met_time(&self) -> u64 { pub fn get_met_time(&self) -> u64 {
let time = self.time.borrow(); let time = self.time.borrow();
time.time_driver.get_monotonic_time(time.time_data) time.time_driver.get_monotonic_time(time.time_data)
} }
/// Time in microseconds relative to system epoch /// Get system time
///
/// This method returns the time in microseconds relative to the system epoch.
/// It is useful for timestamping events and correlating with external systems.
///
/// # Returns
/// * Time in microseconds relative to the system epoch
pub fn get_system_time(&self) -> u64 { pub fn get_system_time(&self) -> u64 {
let time = self.time.borrow(); let time = self.time.borrow();
time.time_driver.get_system_time(time.time_data) time.time_driver.get_system_time(time.time_data)
} }
} }
/// Application trait for RFE applications
///
/// This trait defines the interface for applications to interact with the RFE framework.
/// Applications must implement this trait to be scheduled by the RFE framework.
pub trait App { pub trait App {
/// Initialize the application
///
/// This method is called once when the application is added to the RFE instance.
/// Use this method to set up subscriptions and initialize the application state.
fn init(&mut self, rfe: &mut Rfe) -> Result<()>; fn init(&mut self, rfe: &mut Rfe) -> Result<()>;
/// Run the application
///
/// This method is called at the rate specified by `get_app_rate()`.
/// Use this method to perform the main application logic.
fn run(&mut self, rfe: &mut Rfe); fn run(&mut self, rfe: &mut Rfe);
/// Generate housekeeping data
///
/// This method is called at the rate specified by the RFE instance.
/// Use this method to generate housekeeping data for telemetry.
fn hk(&mut self, rfe: &mut Rfe); fn hk(&mut self, rfe: &mut Rfe);
/// Generate output data
///
/// This method is called at the rate specified by the RFE instance.
/// Use this method to generate output data for telemetry.
fn out_data(&mut self, rfe: &mut Rfe); fn out_data(&mut self, rfe: &mut Rfe);
/// Get the application rate
///
/// This method returns the rate at which the application should be run.
fn get_app_rate(&self) -> Rate; fn get_app_rate(&self) -> Rate;
} }
impl<'a> RfeInstance<'a> { impl<'a> RfeInstance<'a> {
/// Create a new RFE instance
///
/// This method creates a new RFE instance with the specified instance identifier
/// and time driver. The instance identifier is used to identify this instance
/// when communicating with other instances.
///
/// # Arguments
/// * `instance` - The instance identifier
/// * `time_driver` - The time driver to use for time management
///
/// # Returns
/// * A new RFE instance
pub fn new(instance: Instance, time_driver: &'a dyn TimeDriver) -> Self { pub fn new(instance: Instance, time_driver: &'a dyn TimeDriver) -> Self {
let time = Rc::new(RefCell::new(RfeTime { let time = Rc::new(RefCell::new(RfeTime {
time_data: TimeData { time_data: TimeData {
@@ -166,32 +352,50 @@ impl<'a> RfeInstance<'a> {
} }
} }
/// Add an application to the RFE instance
///
/// # Arguments
/// * `name` - The name of the application
/// * `app` - The application to add
///
/// # Returns
/// * `Ok(())` - If the application was added successfully
/// * `Err(...)` - If the application could not be added
pub fn add_app(&mut self, name: &'a str, app: &'a mut dyn App) -> Result<()> { pub fn add_app(&mut self, name: &'a str, app: &'a mut dyn App) -> Result<()> {
if self.app_list.contains_key(name) { if self.app_list.contains_key(name) {
return Err(anyhow!( return Err(anyhow!(
"failed to add app {name}, already added an app with that name" "Failed to add app '{name}': an app with that name already exists"
)); ));
} }
let app_rate = app.get_app_rate(); let app_rate = app.get_app_rate();
self.app_list.insert( self.app_list.insert(
name, name,
AppRef { AppRef {
app: app, app,
app_rate: app_rate, app_rate,
hk_rate: Rate::Hz1, hk_rate: Rate::Hz1,
out_data_rate: app_rate, out_data_rate: app_rate,
rfe: Rfe::new(self.instance, self.time.clone()), rfe: Rfe::new(self.instance, self.time.clone()),
}, },
); );
// Initialize the application
let appref = self.app_list.get_mut(name).unwrap(); let appref = self.app_list.get_mut(name).unwrap();
if let Err(e) = appref.app.init(&mut appref.rfe) { if let Err(e) = appref.app.init(&mut appref.rfe) {
error!("app {name} failed to initialize {e}"); error!("App '{name}' failed to initialize: {e}");
} }
return Ok(()); Ok(())
} }
/// Add a connector to the RFE instance
///
/// Connectors are used to communicate with other RFE instances.
/// They can be used to send and receive messages between instances.
///
/// # Arguments
/// * `connector` - The connector to add
pub fn add_connector(&mut self, connector: &'a mut dyn Connector) { pub fn add_connector(&mut self, connector: &'a mut dyn Connector) {
self.connectors.push(ConnectorState { self.connectors.push(ConnectorState {
connector, connector,
@@ -201,40 +405,31 @@ impl<'a> RfeInstance<'a> {
}); });
} }
/// Expected to be called at 100Hz /// Run the RFE instance
///
/// This method should be called at 100Hz to schedule applications and process messages.
/// It runs applications, collects messages, and routes them to the appropriate destinations.
pub fn run(&mut self) { pub fn run(&mut self) {
let mut msgs = Vec::new(); let mut msgs = Vec::new();
// Run applications and collect messages
for app in self.app_list.values_mut() { for app in self.app_list.values_mut() {
if app.app_rate == Rate::Hz100 // Check if the application should run at this tick
|| (self.sch_counter % 2 == 0 && app.app_rate == Rate::Hz50) if self.should_run_at_rate(app.app_rate) {
|| (self.sch_counter % 5 == 0 && app.app_rate == Rate::Hz20)
|| (self.sch_counter % 10 == 0 && app.app_rate == Rate::Hz10)
|| (self.sch_counter % 20 == 0 && app.app_rate == Rate::Hz5)
|| (self.sch_counter % 100 == 0 && app.app_rate == Rate::Hz1)
{
app.app.run(&mut app.rfe); app.app.run(&mut app.rfe);
} }
if app.hk_rate == Rate::Hz100 // Check if housekeeping should run at this tick
|| (self.sch_counter % 2 == 0 && app.hk_rate == Rate::Hz50) if self.should_run_at_rate(app.hk_rate) {
|| (self.sch_counter % 5 == 0 && app.hk_rate == Rate::Hz20)
|| (self.sch_counter % 10 == 0 && app.hk_rate == Rate::Hz10)
|| (self.sch_counter % 20 == 0 && app.hk_rate == Rate::Hz5)
|| (self.sch_counter % 100 == 0 && app.hk_rate == Rate::Hz1)
{
app.app.hk(&mut app.rfe); app.app.hk(&mut app.rfe);
} }
if app.out_data_rate == Rate::Hz100 // Check if output data should run at this tick
|| (self.sch_counter % 2 == 0 && app.out_data_rate == Rate::Hz50) if self.should_run_at_rate(app.out_data_rate) {
|| (self.sch_counter % 5 == 0 && app.out_data_rate == Rate::Hz20)
|| (self.sch_counter % 10 == 0 && app.out_data_rate == Rate::Hz10)
|| (self.sch_counter % 20 == 0 && app.out_data_rate == Rate::Hz5)
|| (self.sch_counter % 100 == 0 && app.out_data_rate == Rate::Hz1)
{
app.app.out_data(&mut app.rfe); app.app.out_data(&mut app.rfe);
} }
// Collect messages from the application
let new_msgs = core::mem::take(&mut app.rfe.msgs_to_send); let new_msgs = core::mem::take(&mut app.rfe.msgs_to_send);
msgs.extend(new_msgs); msgs.extend(new_msgs);
} }
@@ -365,7 +560,30 @@ impl<'a> RfeInstance<'a> {
self.sch_counter += 1; self.sch_counter += 1;
} }
/// Helper method to determine if a task should run at the given rate
///
/// # Arguments
/// * `rate` - The rate to check
///
/// # Returns
/// * `true` - If the task should run at this tick
/// * `false` - If the task should not run at this tick
fn should_run_at_rate(&self, rate: Rate) -> bool {
match rate {
Rate::Hz100 => true,
Rate::Hz50 => self.sch_counter % 2 == 0,
Rate::Hz20 => self.sch_counter % 5 == 0,
Rate::Hz10 => self.sch_counter % 10 == 0,
Rate::Hz5 => self.sch_counter % 20 == 0,
Rate::Hz1 => self.sch_counter % 100 == 0,
}
}
#[cfg(feature = "std")] #[cfg(feature = "std")]
/// Start the RFE instance
///
/// This method starts the RFE instance and runs it at 100Hz.
/// It blocks the current thread and never returns.
pub fn start(&mut self) { pub fn start(&mut self) {
use core::time::Duration; use core::time::Duration;
use std::{thread::sleep, time::Instant}; use std::{thread::sleep, time::Instant};
+44 -2
View File
@@ -1,17 +1,59 @@
/*!
* Time management module for RFE
*
* This module provides time management functionality for the RFE framework,
* including:
* - Timestamp type for representing time
* - TimeData struct for storing time-related data
* - TimeDriver trait for platform-specific time implementations
* - Various TimeDriver implementations for different platforms
*/
/// Microseconds timestamp /// Microseconds timestamp
///
/// This type represents time in microseconds, either as a duration or
/// as an absolute time relative to some epoch.
pub type Timestamp = u64; pub type Timestamp = u64;
/// Time data for RFE
///
/// This struct stores time-related data for the RFE framework, including
/// the scheduler counter and time offset.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct TimeData { pub struct TimeData {
/// Scheduler counter, incremented on each tick
pub sch_counter: u64, pub sch_counter: u64,
/// Time offset in microseconds
pub time_offset: Timestamp, pub time_offset: Timestamp,
} }
/// Time driver trait
///
/// This trait defines the interface for platform-specific time implementations.
/// It provides methods for getting both system time and monotonic time.
pub trait TimeDriver { pub trait TimeDriver {
/// Time in microseconds relative to system epoch /// Get system time
///
/// This method returns the time in microseconds relative to the system epoch.
/// It is useful for timestamping events and correlating with external systems.
///
/// # Arguments
/// * `time_data` - The time data to use
///
/// # Returns
/// * Time in microseconds relative to the system epoch
fn get_system_time(&self, time_data: TimeData) -> Timestamp; fn get_system_time(&self, time_data: TimeData) -> Timestamp;
/// Time in microseconds since program start or power on /// Get monotonic time
///
/// This method returns the time in microseconds since program start or power on.
/// It is useful for measuring durations and scheduling events.
///
/// # Arguments
/// * `time_data` - The time data to use
///
/// # Returns
/// * Time in microseconds since program start or power on
fn get_monotonic_time(&self, time_data: TimeData) -> Timestamp; fn get_monotonic_time(&self, time_data: TimeData) -> Timestamp;
} }