This commit is contained in:
Jacob Weaver
2024-12-13 10:23:45 -06:00
commit 6b27e84e4b
38 changed files with 2821 additions and 0 deletions
+19
View File
@@ -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
+192
View File
@@ -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
}
}
+72
View File
@@ -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(());
}
}
}
+25
View File
@@ -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(());
}
}