downlink_logfile #21

Merged
lkoester merged 6 commits from downlink_logfile into main 2024-04-25 17:49:19 +02:00
8 changed files with 137 additions and 10 deletions

1
Cargo.lock generated
View File

@ -613,6 +613,7 @@ dependencies = [
"log", "log",
"mio", "mio",
"num_enum", "num_enum",
"once_cell",
"satrs", "satrs",
"satrs-mib", "satrs-mib",
"serde", "serde",

View File

@ -21,6 +21,7 @@ serde_json = "1"
mio = "0.8" mio = "0.8"
homedir = "0.2" homedir = "0.2"
socket2 = "0.5" socket2 = "0.5"
once_cell = "1.19"
[dependencies.satrs] [dependencies.satrs]
version = "0.2.0-rc.5" version = "0.2.0-rc.5"

View File

@ -96,6 +96,16 @@ def create_cmd_definition_tree() -> CmdTreeNode:
CmdTreeNode("custom_params", "Custom Camera Parameters as specified from file") CmdTreeNode("custom_params", "Custom Camera Parameters as specified from file")
) )
action_node.add_child(cam_node) action_node.add_child(cam_node)
controller_node = CmdTreeNode("controller", "Main OBSW Controller")
controller_node.add_child(
CmdTreeNode("downlink_logs", "Downlink Logs via toGround folder")
)
controller_node.add_child(
CmdTreeNode("downlink_last_img", "Downlink last image via toGroundLP folder")
)
action_node.add_child(controller_node)
root_node.add_child(action_node) root_node.add_child(action_node)
return root_node return root_node
@ -157,7 +167,18 @@ def pack_pus_telecommands(q: DefaultPusQueueHelper, cmd_path: str):
service=8, subservice=128, apid=EXPERIMENT_APID, app_data=data service=8, subservice=128, apid=EXPERIMENT_APID, app_data=data
) )
) )
if cmd_path_list[1] == "controller":
assert len(cmd_path_list) >= 3
data = bytearray()
if cmd_path_list[2] == "downlink_logs":
data.extend(make_action_cmd_header(UniqueId.Controller, 2))
if cmd_path_list[2] == "downlink_last_img":
data.extend(make_action_cmd_header(UniqueId.Controller, 3))
return q.add_pus_tc(
PusTelecommand(
service=8, subservice=128, apid=EXPERIMENT_APID, app_data=data
)
)
def handle_set_mode_cmd( def handle_set_mode_cmd(
q: DefaultPusQueueHelper, target_str: str, mode_str: str, apid: int, unique_id: int q: DefaultPusQueueHelper, target_str: str, mode_str: str, apid: int, unique_id: int

View File

@ -9,7 +9,9 @@ use std::path::{Path, PathBuf};
pub const STOP_FILE_NAME: &str = "stop-experiment"; pub const STOP_FILE_NAME: &str = "stop-experiment";
pub const CONFIG_FILE_NAME: &str = "exp278.toml"; pub const CONFIG_FILE_NAME: &str = "exp278.toml";
pub const HOME_FOLDER_EXPERIMENT: &str = "/home/exp278"; pub const HOME_FOLDER_EXPERIMENT: &str = "/home/exp278"; // also where IMS-100 images are placed
pub const TO_GROUND_FOLDER_EXPERIMENT: &str = "/home/exp278/toGround";
pub const TO_GROUND_LP_FOLDER_EXPERIMENT: &str = "/home/exp278/toGroundLP";
pub const LOG_FOLDER: &str = "logs"; pub const LOG_FOLDER: &str = "logs";
pub const OBSW_SERVER_ADDR: Ipv4Addr = Ipv4Addr::UNSPECIFIED; pub const OBSW_SERVER_ADDR: Ipv4Addr = Ipv4Addr::UNSPECIFIED;
@ -291,3 +293,15 @@ pub mod tasks {
pub const STOP_CHECK_FREQUENCY_MS: u64 = 400; pub const STOP_CHECK_FREQUENCY_MS: u64 = 400;
pub const STOP_CHECK_FREQUENCY: Duration = Duration::from_millis(STOP_CHECK_FREQUENCY_MS); pub const STOP_CHECK_FREQUENCY: Duration = Duration::from_millis(STOP_CHECK_FREQUENCY_MS);
} }
pub fn create_low_priority_ground_dir() {
log::info!("Creating low priority to ground directory");
if !Path::new(TO_GROUND_LP_FOLDER_EXPERIMENT).exists()
&& std::fs::create_dir_all(TO_GROUND_LP_FOLDER_EXPERIMENT).is_err()
{
log::error!(
"Failed to create low priority to ground directory '{}'",
TO_GROUND_LP_FOLDER_EXPERIMENT
);
}
}

View File

@ -1,4 +1,10 @@
use crate::logger::LOGFILE_PATH;
use num_enum::TryFromPrimitive; use num_enum::TryFromPrimitive;
use ops_sat_rs::config::{
action_err::INVALID_ACTION_ID, HOME_FOLDER_EXPERIMENT, HOME_PATH, STOP_FILE_NAME,
TO_GROUND_FOLDER_EXPERIMENT,
};
use satrs::action::ActionRequestVariant;
use satrs::{ use satrs::{
action::ActionRequest, action::ActionRequest,
pus::action::{ActionReplyPus, ActionReplyVariant}, pus::action::{ActionReplyPus, ActionReplyVariant},
@ -10,14 +16,14 @@ use std::{
sync::{atomic::AtomicBool, mpsc, Arc}, sync::{atomic::AtomicBool, mpsc, Arc},
}; };
use ops_sat_rs::config::{action_err::INVALID_ACTION_ID, HOME_PATH, STOP_FILE_NAME};
use crate::requests::CompositeRequest; use crate::requests::CompositeRequest;
#[derive(Debug, Clone, Copy, TryFromPrimitive)] #[derive(Debug, Clone, Copy, TryFromPrimitive)]
#[repr(u32)] #[repr(u32)]
pub enum ActionId { pub enum ActionId {
StopExperiment = 1, StopExperiment = 1,
DownlinkLogfile = 2,
DownlinkImages = 3,
} }
pub struct ExperimentController { pub struct ExperimentController {
@ -96,7 +102,45 @@ impl ExperimentController {
ActionReplyVariant::Completed, ActionReplyVariant::Completed,
)); ));
if result.is_err() { if result.is_err() {
log::error!("sending action reply failed"); log::error!("Sending action reply failed");
}
}
ActionId::DownlinkLogfile => {
log::info!("Copying logfile into downlink folder");
if let Some(logfile_path) = LOGFILE_PATH.get() {
if let Ok(logfile_path) = <PathBuf as Clone>::clone(logfile_path)
.into_os_string()
.into_string()
{
if std::fs::copy(logfile_path.as_str(), TO_GROUND_FOLDER_EXPERIMENT)
.is_err()
{
log::error!("Copying logfile into downlink path failed")
}
}
} else {
log::error!("Downlink path emtpy")
}
}
// downlink images, default will be the last image, otherwise specified counting down (2 = second to last image, etc.)
ActionId::DownlinkImages => {
log::info!("Copying images into low priority downlink folder");
if let Ok(image_path) = match action_req.variant {
ActionRequestVariant::VecData(data) => {
let index = data[0];
get_latest_image(index as usize)
}
_ => get_latest_image(0),
} {
if let Ok(image_path) = <PathBuf as Clone>::clone(&image_path)
.into_os_string()
.into_string()
{
if std::fs::copy(image_path, TO_GROUND_FOLDER_EXPERIMENT).is_err() {
log::error!("Copying logfile into downlink path failed")
}
}
} }
} }
} }
@ -126,3 +170,35 @@ impl ExperimentController {
check_at_path(self.home_path_stop_file.as_path()); check_at_path(self.home_path_stop_file.as_path());
} }
} }
// TODO no idea if this works in any way shape or form
pub fn get_latest_image(index: usize) -> Result<PathBuf, std::io::Error> {
// Get the most recently modified file
let mut png_files = std::fs::read_dir(HOME_FOLDER_EXPERIMENT)?
.flatten()
.filter(|f| match f.metadata() {
Ok(metadata) => metadata.is_file(),
Err(_) => false,
})
.filter(|f| match f.file_name().into_string() {
Ok(name) => name.ends_with(".png"),
Err(_) => false,
})
.collect::<Vec<std::fs::DirEntry>>();
png_files.sort_by_key(|x| match x.metadata() {
Ok(metadata) => {
if let Ok(time) = metadata.modified() {
time
} else {
std::time::SystemTime::UNIX_EPOCH
}
}
Err(_) => std::time::SystemTime::UNIX_EPOCH,
});
png_files.reverse();
if let Some(png) = png_files.into_iter().nth(index) {
return Ok(png.path());
}
Err(std::io::Error::other("No latest image found"))
}

View File

@ -291,7 +291,7 @@ impl IMS100BatchHandler {
}, },
}; };
let output = self.take_picture(param)?; let output = self.take_picture(param)?;
debug!("Sending action reply!"); info!("Sending action reply!");
send_data_reply(self.id, output.stdout, &self.stamp_helper, &self.tm_tx)?; send_data_reply(self.id, output.stdout, &self.stamp_helper, &self.tm_tx)?;
self.action_reply_tx self.action_reply_tx
.send(GenericMessage::new( .send(GenericMessage::new(

View File

@ -1,13 +1,25 @@
use once_cell::sync::OnceCell;
use ops_sat_rs::config::LOG_FOLDER;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use ops_sat_rs::config::LOG_FOLDER; pub static LOGFILE_PATH: OnceCell<PathBuf> = OnceCell::new();
pub fn setup_logger() -> Result<(), fern::InitError> { pub fn setup_logger() -> Result<(), fern::InitError> {
if !Path::new(LOG_FOLDER).exists() && std::fs::create_dir_all(LOG_FOLDER).is_err() { if !Path::new(LOG_FOLDER).exists() && std::fs::create_dir_all(LOG_FOLDER).is_err() {
eprintln!("Failed to create log folder '{}'", LOG_FOLDER); eprintln!("Failed to create log folder '{}'", LOG_FOLDER);
} }
let mut path_buf = PathBuf::from(LOG_FOLDER); let mut path_buf = PathBuf::from(LOG_FOLDER);
path_buf.push("output.log"); path_buf.push(
format!(
"output_{}.log",
humantime::format_rfc3339_seconds(std::time::SystemTime::now()).to_string()
)
.replace(":", "_"),
);
println!("Creating logfile {:?}", path_buf);
LOGFILE_PATH
.set(path_buf.clone())
.expect("Error setting global logfile path");
fern::Dispatch::new() fern::Dispatch::new()
.format(move |out, message, record| { .format(move |out, message, record| {
out.finish(format_args!( out.finish(format_args!(

View File

@ -5,10 +5,11 @@ use std::{
time::Duration, time::Duration,
}; };
use log::info; use log::{debug, info};
use ops_sat_rs::config::{ use ops_sat_rs::config::{
cfg_file::create_app_config, cfg_file::create_app_config,
components::{CONTROLLER_ID, TCP_SERVER, TCP_SPP_CLIENT, UDP_SERVER}, components::{CONTROLLER_ID, TCP_SERVER, TCP_SPP_CLIENT, UDP_SERVER},
create_low_priority_ground_dir,
pool::create_sched_tc_pool, pool::create_sched_tc_pool,
tasks::{FREQ_MS_CAMERA_HANDLING, FREQ_MS_CTRL, FREQ_MS_PUS_STACK, STOP_CHECK_FREQUENCY}, tasks::{FREQ_MS_CAMERA_HANDLING, FREQ_MS_CTRL, FREQ_MS_PUS_STACK, STOP_CHECK_FREQUENCY},
VALID_PACKET_ID_LIST, VERSION, VALID_PACKET_ID_LIST, VERSION,
@ -55,9 +56,10 @@ fn main() {
setup_logger().expect("setting up logging with fern failed"); setup_logger().expect("setting up logging with fern failed");
let version_str = VERSION.unwrap_or("?"); let version_str = VERSION.unwrap_or("?");
println!("OPS-SAT Rust Experiment OBSW v{}", version_str); println!("OPS-SAT Rust Experiment OBSW v{}", version_str);
create_low_priority_ground_dir();
let app_cfg = create_app_config(); let app_cfg = create_app_config();
println!("App Configuration: {:?}", app_cfg); info!("App Configuration: {:?}", app_cfg);
let stop_signal = Arc::new(AtomicBool::new(false)); let stop_signal = Arc::new(AtomicBool::new(false));