158 lines
4.1 KiB
Rust
158 lines
4.1 KiB
Rust
extern crate alloc;
|
|
|
|
use std::{
|
|
sync::mpsc,
|
|
time::{Duration, Instant},
|
|
};
|
|
|
|
pub use models::ComponentId;
|
|
use models::ccsds::{CcsdsTcPacketOwned, CcsdsTmPacketOwned};
|
|
use satrs::spacepackets::{CcsdsPacketIdAndPsc, time::cds::CdsTime};
|
|
|
|
pub mod config;
|
|
|
|
/// Simple type modelling packet stored in the heap. This structure is intended to
|
|
/// be used when sending a packet via a message queue, so it also contains the sender ID.
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
pub struct PacketAsVec {
|
|
pub sender_id: ComponentId,
|
|
pub packet: Vec<u8>,
|
|
}
|
|
|
|
impl PacketAsVec {
|
|
pub fn new(sender_id: ComponentId, packet: Vec<u8>) -> Self {
|
|
Self { sender_id, packet }
|
|
}
|
|
}
|
|
|
|
pub struct TimestampHelper {
|
|
stamper: CdsTime,
|
|
time_stamp: [u8; 7],
|
|
}
|
|
|
|
impl TimestampHelper {
|
|
pub fn stamp(&self) -> &[u8] {
|
|
&self.time_stamp
|
|
}
|
|
|
|
pub fn update_from_now(&mut self) {
|
|
self.stamper
|
|
.update_from_now()
|
|
.expect("Updating timestamp failed");
|
|
self.stamper
|
|
.write_to_bytes(&mut self.time_stamp)
|
|
.expect("Writing timestamp failed");
|
|
}
|
|
}
|
|
|
|
impl Default for TimestampHelper {
|
|
fn default() -> Self {
|
|
Self {
|
|
stamper: CdsTime::now_with_u16_days().expect("creating time stamper failed"),
|
|
time_stamp: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Helper structure for periodic HK generation of a single set.
|
|
#[derive(Debug)]
|
|
pub struct HkHelperSingleSet {
|
|
pub enabled: bool,
|
|
pub frequency: Duration,
|
|
pub last_generated: Option<Instant>,
|
|
}
|
|
|
|
impl HkHelperSingleSet {
|
|
#[inline]
|
|
pub const fn new(enabled: bool, init_frequency: Duration) -> Self {
|
|
Self {
|
|
enabled,
|
|
frequency: init_frequency,
|
|
last_generated: None,
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn enabled(&self) -> bool {
|
|
self.enabled
|
|
}
|
|
|
|
/// Check whether a new HK packet needs to be generated.
|
|
pub fn needs_generation(&mut self) -> bool {
|
|
if !self.enabled {
|
|
return false;
|
|
}
|
|
if self.last_generated.is_none() {
|
|
self.last_generated = Some(Instant::now());
|
|
return true;
|
|
}
|
|
let last_generated = self.last_generated.unwrap();
|
|
if Instant::now() - last_generated >= self.frequency {
|
|
self.last_generated = Some(Instant::now());
|
|
return true;
|
|
}
|
|
false
|
|
}
|
|
}
|
|
|
|
pub struct TmtcQueues {
|
|
pub tc_rx: mpsc::Receiver<CcsdsTcPacketOwned>,
|
|
pub tm_tx: mpsc::SyncSender<CcsdsTmPacketOwned>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct ModeHelper<Mode, TransitionState> {
|
|
pub current: Mode,
|
|
pub target: Option<Mode>,
|
|
pub tc_commander: Option<CcsdsPacketIdAndPsc>,
|
|
pub transition_start: Option<Instant>,
|
|
pub timeout: Duration,
|
|
pub transition_state: TransitionState,
|
|
}
|
|
|
|
impl<Mode: Copy + Clone, TransitionState: Default> ModeHelper<Mode, TransitionState> {
|
|
pub fn new(init_mode: Mode, timeout: Duration) -> Self {
|
|
Self {
|
|
current: init_mode,
|
|
target: Default::default(),
|
|
tc_commander: Default::default(),
|
|
transition_start: None,
|
|
timeout,
|
|
transition_state: Default::default(),
|
|
}
|
|
}
|
|
|
|
pub fn start(&mut self, target: Mode) {
|
|
self.target = Some(target);
|
|
self.transition_start = Some(Instant::now());
|
|
self.transition_state = TransitionState::default();
|
|
}
|
|
|
|
#[inline]
|
|
pub fn transition_active(&self) -> bool {
|
|
self.target.is_some()
|
|
}
|
|
|
|
pub fn timed_out(&self) -> bool {
|
|
if self.target.is_none() {
|
|
return false;
|
|
}
|
|
if let Some(transition_start) = self.transition_start {
|
|
return Instant::now() - transition_start >= self.timeout;
|
|
}
|
|
false
|
|
}
|
|
|
|
pub fn finish(&mut self, success: bool) -> Option<CcsdsPacketIdAndPsc> {
|
|
self.target?;
|
|
if success {
|
|
self.current = self.target.take().unwrap();
|
|
} else {
|
|
self.target = None;
|
|
}
|
|
self.transition_state = Default::default();
|
|
self.transition_start = None;
|
|
self.tc_commander.take()
|
|
}
|
|
}
|