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);
lkoester marked this conversation as resolved Outdated

I'd leave this a println. There are corner cases where logger output ca nbe invisible, and I always want to see this line at the very least.

I'd leave this a println. There are corner cases where logger output ca nbe invisible, and I always want to see this line at the very least.
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);
lkoester marked this conversation as resolved Outdated

I'd transform this to INFO. debug is usually not visible, and this is valuable information, as long as it's not too noisy.

I'd transform this to INFO. debug is usually not visible, and this is valuable information, as long as it's not too noisy.
let stop_signal = Arc::new(AtomicBool::new(false)); let stop_signal = Arc::new(AtomicBool::new(false));