firstadd
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "ds"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
path = "src/ds.rs"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
|
||||
[dependencies]
|
||||
rfe = { path = "../../rfe" }
|
||||
anyhow.workspace = true
|
||||
log.workspace = true
|
||||
chrono = "0.4.38"
|
||||
bincode.workspace = true
|
||||
hashbrown.workspace = true
|
||||
@@ -0,0 +1,192 @@
|
||||
#![no_std]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod ds_std;
|
||||
use bincode::encode_to_vec;
|
||||
#[cfg(feature = "std")]
|
||||
pub use ds_std::DsFile;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
mod ds_stub;
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub use ds_stub::DsFile;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use anyhow::Result;
|
||||
use hashbrown::HashMap;
|
||||
use log::*;
|
||||
use msg::{DsCmd, DsHk, DsOutData, DsTlmSet, Instance, Msg, TlmSetId};
|
||||
use rfe::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct DsData {
|
||||
hk: DsHk,
|
||||
out_data: DsOutData,
|
||||
file_list: HashMap<TlmSetId, DsFile>,
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
pub struct DsFileSettings {
|
||||
pub max_size: u32,
|
||||
pub max_age: u32,
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
pub struct Ds {
|
||||
data: DsData,
|
||||
tlm_sets: HashMap<TlmSetId, DsTlmSet>,
|
||||
start_enabled: bool,
|
||||
}
|
||||
|
||||
impl Ds {
|
||||
pub fn new(tlm_sets: HashMap<TlmSetId, DsTlmSet>, start_enabled: bool) -> Self {
|
||||
Self {
|
||||
data: Default::default(),
|
||||
tlm_sets,
|
||||
start_enabled,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_subscriptions(&mut self, rfe: &mut Rfe) {
|
||||
rfe.unsubscribe_all();
|
||||
rfe.subscribe_all(
|
||||
self.tlm_sets
|
||||
.values()
|
||||
.filter(|x| x.enabled)
|
||||
.map(|x| &x.items)
|
||||
.flatten()
|
||||
.map(|x| x.target),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl App for Ds {
|
||||
fn init(&mut self, rfe: &mut rfe::Rfe) -> Result<()> {
|
||||
self.data = Default::default();
|
||||
self.data.enabled = self.start_enabled;
|
||||
|
||||
self.update_subscriptions(rfe);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn run(&mut self, rfe: &mut rfe::Rfe) {
|
||||
self.data.out_data.counter += 1;
|
||||
self.data.out_data.bytes_written_this_cycle = 0;
|
||||
while let Some(msg) = rfe.recv() {
|
||||
match msg.msg {
|
||||
Msg::DsCmd(cmd) => match cmd {
|
||||
DsCmd::Noop => info!("Noop command received"),
|
||||
DsCmd::Reset => {
|
||||
info!("Reset command received");
|
||||
self.data = Default::default();
|
||||
}
|
||||
DsCmd::CloseAll => {
|
||||
info!("CloseAll command received");
|
||||
for f in self.data.file_list.values_mut() {
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
DsCmd::Close(f) => {
|
||||
info!("Close command received");
|
||||
if let Some(file) = self.data.file_list.get_mut(&f) {
|
||||
file.close();
|
||||
} else {
|
||||
error!("Cannot close file {f}, file doesn't exist");
|
||||
}
|
||||
}
|
||||
DsCmd::AddTlmSet(ds_tlm_set) => {
|
||||
info!("received AddTlmSet");
|
||||
if let Err(e) = self.tlm_sets.try_insert(ds_tlm_set.id, ds_tlm_set.clone())
|
||||
{
|
||||
error!("Could not add tlm set {} {e}", ds_tlm_set.id);
|
||||
} else {
|
||||
info!("TlmSet {} added", ds_tlm_set.id);
|
||||
self.update_subscriptions(rfe);
|
||||
}
|
||||
}
|
||||
DsCmd::RemoveTlmSet(set_id) => {
|
||||
info!("received RemoveTlmSet");
|
||||
if let Some(_set) = self.tlm_sets.remove(&set_id) {
|
||||
info!("removed tlm set {}", set_id);
|
||||
self.update_subscriptions(rfe);
|
||||
} else {
|
||||
warn!("Cannot remove tlm set {}, does not exist", set_id);
|
||||
}
|
||||
}
|
||||
DsCmd::DisableTlmSet(set_id) => {
|
||||
info!("received DisableTlmSet");
|
||||
if let Some(set) = self.tlm_sets.get_mut(&set_id) {
|
||||
info!("set {set_id} is now disabled");
|
||||
set.enabled = false;
|
||||
self.update_subscriptions(rfe);
|
||||
} else {
|
||||
warn!("could not disable set {set_id}, does not exist");
|
||||
}
|
||||
}
|
||||
DsCmd::EnablTlmSet(set_id) => {
|
||||
info!("received EnablTlmSet");
|
||||
if let Some(set) = self.tlm_sets.get_mut(&set_id) {
|
||||
info!("set {set_id} is now enabled");
|
||||
set.enabled = true;
|
||||
self.update_subscriptions(rfe);
|
||||
} else {
|
||||
warn!("could not enable set {set_id}, does not exist");
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
if !self.data.enabled {
|
||||
continue;
|
||||
}
|
||||
|
||||
for tlm_set in self.tlm_sets.values_mut().filter(|x| x.enabled) {
|
||||
for item in &mut tlm_set.items {
|
||||
let msg_target = msg.to_target();
|
||||
if msg_target == item.target
|
||||
|| (msg_target.msg == item.target.msg
|
||||
&& item.target.instance == Instance::All)
|
||||
{
|
||||
if item.counter % (item.decimation + 1) == 0 {
|
||||
let file =
|
||||
if let Some(f) = self.data.file_list.get_mut(&tlm_set.id) {
|
||||
f
|
||||
} else {
|
||||
let f = DsFile::new(tlm_set.path.clone());
|
||||
self.data.file_list.insert(tlm_set.id, f);
|
||||
self.data.file_list.get_mut(&tlm_set.id).unwrap()
|
||||
};
|
||||
|
||||
let bytes = encode_to_vec(&msg, BINCODE_CONFIG)
|
||||
.expect("failed serialize ds packet");
|
||||
if let Err(e) = file.write(&bytes) {
|
||||
error!("file write error: {e}");
|
||||
} else {
|
||||
self.data.out_data.bytes_written_this_cycle +=
|
||||
bytes.len() as u32;
|
||||
}
|
||||
}
|
||||
item.counter += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.data.out_data.bytes_written += self.data.out_data.bytes_written_this_cycle;
|
||||
}
|
||||
|
||||
fn hk(&mut self, rfe: &mut rfe::Rfe) {
|
||||
self.data.hk.counter = self.data.out_data.counter;
|
||||
rfe.send(Msg::DsHk(self.data.hk));
|
||||
}
|
||||
|
||||
fn out_data(&mut self, rfe: &mut rfe::Rfe) {
|
||||
rfe.send(Msg::DsOutData(self.data.out_data));
|
||||
}
|
||||
|
||||
fn get_app_rate(&self) -> Rate {
|
||||
Rate::Hz1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
extern crate std;
|
||||
|
||||
use alloc::{
|
||||
format,
|
||||
string::{String, ToString},
|
||||
};
|
||||
use chrono::Utc;
|
||||
use log::*;
|
||||
use std::{fs::File, io::Write, path::Path};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DsFile {
|
||||
pub dir: String,
|
||||
pub file: Option<File>,
|
||||
prefix: String,
|
||||
}
|
||||
|
||||
impl DsFile {
|
||||
pub fn new(dir: String) -> Self {
|
||||
Self {
|
||||
file: None,
|
||||
prefix: dir
|
||||
.clone()
|
||||
.split("/")
|
||||
.last()
|
||||
.unwrap_or("unnamed")
|
||||
.to_string(),
|
||||
dir,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close(&mut self) {
|
||||
self.file = None;
|
||||
}
|
||||
|
||||
pub fn open(&mut self) {
|
||||
let time = Self::get_time(&self.prefix);
|
||||
let file_path = Path::new(&self.dir).join(time);
|
||||
self.file = match File::create(&file_path) {
|
||||
Ok(f) => Some(f),
|
||||
Err(e) => {
|
||||
error!("failed to create file at {:?} {}", file_path, e);
|
||||
None
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn get_time(prefix: &str) -> String {
|
||||
let date = Utc::now();
|
||||
format!("{}_{}", prefix, date.format("%Y-%m-%d_%H-%M-%S.dat"))
|
||||
}
|
||||
|
||||
pub fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
if self.file.is_none() {
|
||||
self.open();
|
||||
}
|
||||
|
||||
if let Some(f) = &mut self.file {
|
||||
return f.write(buf);
|
||||
} else {
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) -> std::io::Result<()> {
|
||||
if let Some(f) = &mut self.file {
|
||||
return f.flush();
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
use alloc::string::String;
|
||||
use anyhow::Result;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DsFile {
|
||||
pub dir: String,
|
||||
}
|
||||
|
||||
impl DsFile {
|
||||
pub fn new(dir: String) -> Self {
|
||||
Self { dir }
|
||||
}
|
||||
|
||||
pub fn close(&mut self) {}
|
||||
|
||||
pub fn open(&mut self) {}
|
||||
|
||||
pub fn write(&mut self, _buf: &[u8]) -> Result<usize> {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "example"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
path = "src/example.rs"
|
||||
|
||||
[dependencies]
|
||||
rfe = { path = "../../rfe" }
|
||||
anyhow.workspace = true
|
||||
log.workspace = true
|
||||
@@ -0,0 +1,69 @@
|
||||
#![no_std]
|
||||
|
||||
use anyhow::Result;
|
||||
use log::info;
|
||||
use msg::{ExampleCmd, ExampleHk, ExampleOutData, Instance, Msg, MsgKind, TargetMsg};
|
||||
use rfe::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct ExampleData {
|
||||
hk: ExampleHk,
|
||||
out_data: ExampleOutData,
|
||||
}
|
||||
|
||||
pub struct Example {
|
||||
data: ExampleData,
|
||||
}
|
||||
|
||||
impl Example {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
data: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl App for Example {
|
||||
fn init(&mut self, rfe: &mut rfe::Rfe) -> Result<()> {
|
||||
self.data = Default::default();
|
||||
rfe.subscribe(TargetMsg::new(Instance::Other, MsgKind::ExampleHk));
|
||||
rfe.subscribe(TargetMsg::new(rfe.get_instance(), MsgKind::ExampleCmd));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn run(&mut self, rfe: &mut rfe::Rfe) {
|
||||
self.data.out_data.counter += 1;
|
||||
info!("example running {:?}", self.data);
|
||||
while let Some(msg) = rfe.recv() {
|
||||
match msg.msg {
|
||||
Msg::ExampleCmd(cmd) => match cmd {
|
||||
ExampleCmd::Noop => info!("NOOP command received"),
|
||||
ExampleCmd::Reset => {
|
||||
info!("RESET command received");
|
||||
self.data = Default::default();
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
info!("example got msg {:?}", msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.data.out_data.counter > 10 {
|
||||
rfe.send(Msg::ExampleCmd(ExampleCmd::Reset));
|
||||
};
|
||||
}
|
||||
|
||||
fn hk(&mut self, rfe: &mut rfe::Rfe) {
|
||||
self.data.hk.counter = self.data.out_data.counter;
|
||||
rfe.send(Msg::ExampleHk(self.data.hk));
|
||||
}
|
||||
|
||||
fn out_data(&mut self, rfe: &mut rfe::Rfe) {
|
||||
rfe.send(Msg::ExampleOutData(self.data.out_data));
|
||||
}
|
||||
|
||||
fn get_app_rate(&self) -> Rate {
|
||||
Rate::Hz1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "hs"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
path = "src/hs.rs"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = ["dep:sysinfo", "dep:watchdog-device"]
|
||||
|
||||
[dependencies]
|
||||
rfe = { path = "../../rfe" }
|
||||
anyhow.workspace = true
|
||||
log.workspace = true
|
||||
watchdog-device = { version = "0.2.0", optional = true }
|
||||
sysinfo = { version = "0.32.0", default-features = false, optional = true, features = [
|
||||
"component",
|
||||
"disk",
|
||||
"system",
|
||||
] }
|
||||
@@ -0,0 +1,154 @@
|
||||
#![no_std]
|
||||
use anyhow::Result;
|
||||
use log::*;
|
||||
use msg::{HsCmd, HsHk, HsOutData, Msg, MsgKind, TargetMsg};
|
||||
use rfe::*;
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
mod watchdog;
|
||||
use utils::ManualAuto;
|
||||
pub use watchdog::*;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod hs_std;
|
||||
#[cfg(feature = "std")]
|
||||
pub use hs_std::*;
|
||||
|
||||
#[cfg(not(any(feature = "std")))]
|
||||
mod hs_stub;
|
||||
#[cfg(not(any(feature = "std")))]
|
||||
pub use hs_stub::*;
|
||||
|
||||
pub trait SystemInfoGrabber {
|
||||
fn check_cpu_usage(&mut self) -> Vec<u8>;
|
||||
fn check_mem_usage(&mut self) -> u8;
|
||||
fn check_fs_usage(&mut self) -> Vec<u8>;
|
||||
fn check_temps(&mut self) -> Vec<i8>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct HsData {
|
||||
out_data: HsOutData,
|
||||
hk: HsHk,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct HsConfig {
|
||||
pub cpu_checks: bool,
|
||||
pub mem_checks: bool,
|
||||
pub fs_checks: bool,
|
||||
pub temp_checks: bool,
|
||||
pub watchdog_enable: bool,
|
||||
pub watchdog_timeout: i32,
|
||||
}
|
||||
|
||||
pub struct Hs<'a> {
|
||||
data: HsData,
|
||||
config: HsConfig,
|
||||
grabber: &'a mut dyn SystemInfoGrabber,
|
||||
wd: WatchdogRef<'a>,
|
||||
wd_value: ManualAuto<bool>,
|
||||
}
|
||||
|
||||
impl<'a> Hs<'a> {
|
||||
pub fn new(
|
||||
config: HsConfig,
|
||||
grabber: &'a mut dyn SystemInfoGrabber,
|
||||
mut watchdog: WatchdogRef<'a>,
|
||||
) -> Self {
|
||||
if config.watchdog_enable {
|
||||
watchdog.enable();
|
||||
} else {
|
||||
watchdog.disable();
|
||||
}
|
||||
watchdog.set_time(config.watchdog_timeout);
|
||||
Self {
|
||||
data: Default::default(),
|
||||
config,
|
||||
grabber,
|
||||
wd: watchdog,
|
||||
wd_value: ManualAuto::new(config.watchdog_enable, false),
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.data = Default::default();
|
||||
}
|
||||
}
|
||||
|
||||
impl App for Hs<'_> {
|
||||
fn init(&mut self, rfe: &mut Rfe) -> Result<()> {
|
||||
self.reset();
|
||||
rfe.subscribe(TargetMsg::new(rfe.get_instance(), MsgKind::HsCmd));
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn run(&mut self, rfe: &mut Rfe) {
|
||||
self.data.out_data.counter += 1;
|
||||
while let Some(msg) = rfe.recv() {
|
||||
match msg.msg {
|
||||
Msg::HsCmd(cmd) => {
|
||||
self.data.hk.cmd_counter += 1;
|
||||
match cmd {
|
||||
HsCmd::Noop => {
|
||||
info!("Noop command received");
|
||||
}
|
||||
HsCmd::Reset => {
|
||||
info!("Reset command received");
|
||||
self.data = Default::default();
|
||||
}
|
||||
HsCmd::WatchdogEnableManual(v) => self.wd_value.manual_set(v),
|
||||
HsCmd::WatchdogEnableAuto(v) => self.wd_value.auto_set(v),
|
||||
HsCmd::WatchdogResumeAuto => self.wd_value.resume_auto(),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
warn!(
|
||||
"HS received unexpected message: {:?} from {:?}",
|
||||
msg.msg.kind(),
|
||||
msg.instance
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.wd_value.has_changed() {
|
||||
if *self.wd_value.get() {
|
||||
self.wd.enable();
|
||||
} else {
|
||||
self.wd.disable();
|
||||
}
|
||||
}
|
||||
self.wd.feed();
|
||||
|
||||
if self.config.cpu_checks {
|
||||
self.data.hk.cpu_usage = self.grabber.check_cpu_usage();
|
||||
}
|
||||
if self.config.mem_checks {
|
||||
self.data.hk.mem_usage = self.grabber.check_mem_usage();
|
||||
}
|
||||
if self.config.fs_checks {
|
||||
self.data.hk.fs_usage = self.grabber.check_fs_usage();
|
||||
}
|
||||
if self.config.temp_checks {
|
||||
self.data.hk.temps = self.grabber.check_temps();
|
||||
}
|
||||
}
|
||||
|
||||
fn hk(&mut self, rfe: &mut Rfe) {
|
||||
self.data.hk.counter = self.data.out_data.counter;
|
||||
|
||||
rfe.send(Msg::HsHk(self.data.hk.clone()));
|
||||
}
|
||||
|
||||
fn out_data(&mut self, rfe: &mut Rfe) {
|
||||
rfe.send(Msg::HsOutData(self.data.out_data));
|
||||
}
|
||||
|
||||
fn get_app_rate(&self) -> Rate {
|
||||
Rate::Hz1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
use sysinfo::{Components, CpuRefreshKind, Disks, MemoryRefreshKind, RefreshKind, System};
|
||||
|
||||
use crate::SystemInfoGrabber;
|
||||
extern crate alloc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
pub struct StdSystemInfoGrabber {
|
||||
system: System,
|
||||
}
|
||||
|
||||
impl StdSystemInfoGrabber {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
system: System::new_with_specifics(
|
||||
RefreshKind::new()
|
||||
.with_cpu(CpuRefreshKind::new().with_cpu_usage())
|
||||
.with_memory(MemoryRefreshKind::new().with_ram()),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SystemInfoGrabber for StdSystemInfoGrabber {
|
||||
fn check_cpu_usage(&mut self) -> Vec<u8> {
|
||||
self.system.refresh_cpu_usage();
|
||||
self.system
|
||||
.cpus()
|
||||
.iter()
|
||||
.map(|x| x.cpu_usage().round() as u8)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn check_mem_usage(&mut self) -> u8 {
|
||||
self.system.refresh_memory();
|
||||
(self.system.used_memory() * 100 / self.system.total_memory()) as u8
|
||||
}
|
||||
|
||||
fn check_fs_usage(&mut self) -> Vec<u8> {
|
||||
let mut disks = Disks::new_with_refreshed_list();
|
||||
let disks = disks.list_mut();
|
||||
disks.sort_by(|x, y| x.name().cmp(y.name()));
|
||||
|
||||
disks
|
||||
.iter()
|
||||
.map(|x| ((x.total_space() - x.available_space()) * 100 / x.total_space()) as u8)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn check_temps(&mut self) -> Vec<i8> {
|
||||
let mut components = Components::new_with_refreshed_list();
|
||||
let components = components.list_mut();
|
||||
components.sort_by(|x, y| x.label().cmp(y.label()));
|
||||
|
||||
components
|
||||
.iter()
|
||||
.map(|x| x.temperature().round() as i8)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
pub trait Watchdog {
|
||||
fn enable(&mut self);
|
||||
fn disable(&mut self);
|
||||
fn set_time(&mut self, time: i32);
|
||||
fn feed(&mut self);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod watchdog_std {
|
||||
use super::Watchdog;
|
||||
extern crate std;
|
||||
use crate::unwrap_print_err;
|
||||
use anyhow::Result;
|
||||
use log::*;
|
||||
|
||||
pub struct LinuxWatchdog {
|
||||
wd: watchdog_device::Watchdog,
|
||||
}
|
||||
|
||||
impl LinuxWatchdog {
|
||||
pub fn new() -> Result<Self> {
|
||||
let wd = watchdog_device::Watchdog::new()?;
|
||||
wd.set_option(&watchdog_device::SetOptionFlags::DisableCard)?;
|
||||
Ok(Self { wd })
|
||||
}
|
||||
}
|
||||
|
||||
impl Watchdog for LinuxWatchdog {
|
||||
fn enable(&mut self) {
|
||||
unwrap_print_err!(
|
||||
self.wd
|
||||
.set_option(&watchdog_device::SetOptionFlags::EnableCard),
|
||||
"failed to enable watchdog"
|
||||
);
|
||||
}
|
||||
|
||||
fn disable(&mut self) {
|
||||
unwrap_print_err!(
|
||||
self.wd
|
||||
.set_option(&watchdog_device::SetOptionFlags::DisableCard),
|
||||
"failed to set watchdog timeout"
|
||||
);
|
||||
}
|
||||
|
||||
fn set_time(&mut self, time: i32) {
|
||||
unwrap_print_err!(self.wd.set_timeout(time), "failed to set watchdog timeout");
|
||||
}
|
||||
|
||||
fn feed(&mut self) {
|
||||
unwrap_print_err!(self.wd.keep_alive(), "failed to feed watchdog");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use watchdog_std::*;
|
||||
|
||||
pub type WatchdogRef<'a> = Option<&'a mut dyn Watchdog>;
|
||||
|
||||
impl<'a> Watchdog for Option<&'a mut dyn Watchdog> {
|
||||
fn enable(&mut self) {
|
||||
if let Some(wd) = self {
|
||||
wd.enable();
|
||||
}
|
||||
}
|
||||
|
||||
fn disable(&mut self) {
|
||||
if let Some(wd) = self {
|
||||
wd.disable();
|
||||
}
|
||||
}
|
||||
|
||||
fn set_time(&mut self, time: i32) {
|
||||
if let Some(wd) = self {
|
||||
wd.set_time(time);
|
||||
}
|
||||
}
|
||||
|
||||
fn feed(&mut self) {
|
||||
if let Some(wd) = self {
|
||||
wd.feed();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "to"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
path = "src/to.rs"
|
||||
|
||||
[dependencies]
|
||||
rfe = { path = "../../rfe" }
|
||||
anyhow.workspace = true
|
||||
log.workspace = true
|
||||
hashbrown.workspace = true
|
||||
@@ -0,0 +1,151 @@
|
||||
#![no_std]
|
||||
extern crate alloc;
|
||||
use alloc::vec::Vec;
|
||||
use anyhow::Result;
|
||||
use connector::Connector;
|
||||
use hashbrown::HashMap;
|
||||
use log::*;
|
||||
use msg::{Instance, Msg, MsgKind, TargetMsg, TlmSetId, ToCmd, ToHk, ToOutData, ToTlmSet};
|
||||
use rfe::*;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ToData {
|
||||
out_data: ToOutData,
|
||||
hk: ToHk,
|
||||
}
|
||||
|
||||
pub struct To<'a> {
|
||||
data: ToData,
|
||||
connector: &'a mut dyn Connector,
|
||||
tlm_sets: HashMap<TlmSetId, ToTlmSet>,
|
||||
}
|
||||
|
||||
impl<'a> To<'a> {
|
||||
pub fn new(connector: &'a mut dyn Connector, tlm_sets: HashMap<TlmSetId, ToTlmSet>) -> Self {
|
||||
Self {
|
||||
connector,
|
||||
data: Default::default(),
|
||||
tlm_sets,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_subscriptions(&mut self, rfe: &mut Rfe) {
|
||||
rfe.unsubscribe_all();
|
||||
rfe.subscribe_all(
|
||||
self.tlm_sets
|
||||
.values()
|
||||
.filter(|x| x.enabled)
|
||||
.map(|x| &x.items)
|
||||
.flatten()
|
||||
.map(|x| x.target),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn handle_cmd(&mut self, rfe: &mut Rfe, cmd: &ToCmd) {
|
||||
match cmd {
|
||||
ToCmd::Noop => info!("received Noop"),
|
||||
ToCmd::Reset => {
|
||||
info!("received Reset");
|
||||
self.data = Default::default();
|
||||
}
|
||||
ToCmd::AddTlmSet(to_tlm_set) => {
|
||||
info!("received AddTlmSet");
|
||||
if let Err(e) = self.tlm_sets.try_insert(to_tlm_set.id, to_tlm_set.clone()) {
|
||||
error!("Could not add tlm set {} {e}", to_tlm_set.id);
|
||||
} else {
|
||||
info!("TlmSet {} added", to_tlm_set.id);
|
||||
self.update_subscriptions(rfe);
|
||||
}
|
||||
}
|
||||
ToCmd::RemoveTlmSet(set_id) => {
|
||||
info!("received RemoveTlmSet");
|
||||
if let Some(_set) = self.tlm_sets.remove(set_id) {
|
||||
info!("removed tlm set {}", set_id);
|
||||
self.update_subscriptions(rfe);
|
||||
} else {
|
||||
warn!("Cannot remove tlm set {}, does not exist", set_id);
|
||||
}
|
||||
}
|
||||
ToCmd::DisableTlmSet(set_id) => {
|
||||
info!("received DisableTlmSet");
|
||||
if let Some(set) = self.tlm_sets.get_mut(set_id) {
|
||||
info!("set {set_id} is now disabled");
|
||||
set.enabled = false;
|
||||
self.update_subscriptions(rfe);
|
||||
} else {
|
||||
warn!("could not disable set {set_id}, does not exist");
|
||||
}
|
||||
}
|
||||
ToCmd::EnablTlmSet(set_id) => {
|
||||
info!("received EnablTlmSet");
|
||||
if let Some(set) = self.tlm_sets.get_mut(set_id) {
|
||||
info!("set {set_id} is now enabled");
|
||||
set.enabled = true;
|
||||
self.update_subscriptions(rfe);
|
||||
} else {
|
||||
warn!("could not enable set {set_id}, does not exist");
|
||||
}
|
||||
}
|
||||
}
|
||||
info!("got cmd {:?}", cmd);
|
||||
}
|
||||
}
|
||||
|
||||
impl App for To<'_> {
|
||||
fn init(&mut self, rfe: &mut Rfe) -> Result<()> {
|
||||
rfe.subscribe(TargetMsg::new(rfe.get_instance(), MsgKind::ToCmd));
|
||||
self.update_subscriptions(rfe);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn run(&mut self, rfe: &mut Rfe) {
|
||||
self.data.out_data.counter += 1;
|
||||
let mut msgs = Vec::new();
|
||||
while let Some(msg) = rfe.recv() {
|
||||
let mut is_cmd = false;
|
||||
if let Msg::ToCmd(cmd) = &msg.msg {
|
||||
if msg.instance == rfe.get_instance() {
|
||||
is_cmd = true;
|
||||
self.handle_cmd(rfe, cmd);
|
||||
}
|
||||
}
|
||||
if !is_cmd {
|
||||
for tlm_set in self.tlm_sets.values_mut().filter(|x| x.enabled) {
|
||||
for item in &mut tlm_set.items {
|
||||
let msg_target = msg.to_target();
|
||||
if msg_target == item.target
|
||||
|| (msg_target.msg == item.target.msg
|
||||
&& item.target.instance == Instance::All)
|
||||
{
|
||||
if item.counter % (item.decimation + 1) == 0 {
|
||||
msgs.push(msg.clone());
|
||||
}
|
||||
item.counter += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if msgs.len() > 0 {
|
||||
self.connector.send(msgs);
|
||||
}
|
||||
|
||||
while let Some(msgs) = self.connector.recv() {
|
||||
for msg in msgs {
|
||||
rfe.post_message(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn hk(&mut self, rfe: &mut Rfe) {
|
||||
rfe.send(Msg::ToHk(self.data.hk));
|
||||
}
|
||||
|
||||
fn out_data(&mut self, rfe: &mut Rfe) {
|
||||
rfe.send(Msg::ToOutData(self.data.out_data));
|
||||
}
|
||||
|
||||
fn get_app_rate(&self) -> Rate {
|
||||
Rate::Hz50
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user