some minor cleaning up plus initial image file handling

This commit is contained in:
lkoester 2024-04-19 22:05:57 +02:00
parent 4f94e9cade
commit 0f391c2087
5 changed files with 131 additions and 33 deletions

View File

@ -115,6 +115,7 @@ pub mod components {
UdpServer = 7, UdpServer = 7,
TcpServer = 8, TcpServer = 8,
TcpSppClient = 9, TcpSppClient = 9,
CameraHandler = 10,
} }
pub const CONTROLLER_ID: UniqueApidTargetId = pub const CONTROLLER_ID: UniqueApidTargetId =
@ -137,6 +138,8 @@ pub mod components {
UniqueApidTargetId::new(EXPERIMENT_APID, UniqueId::TcpServer as u32); UniqueApidTargetId::new(EXPERIMENT_APID, UniqueId::TcpServer as u32);
pub const TCP_SPP_CLIENT: UniqueApidTargetId = pub const TCP_SPP_CLIENT: UniqueApidTargetId =
UniqueApidTargetId::new(EXPERIMENT_APID, UniqueId::TcpSppClient as u32); UniqueApidTargetId::new(EXPERIMENT_APID, UniqueId::TcpSppClient as u32);
pub const CAMERA_HANDLER: UniqueApidTargetId =
UniqueApidTargetId::new(EXPERIMENT_APID, UniqueId::CameraHandler as u32);
} }
pub mod tasks { pub mod tasks {

View File

@ -24,7 +24,6 @@
/// v Y /// v Y
/// ///
/// see also https://opssat1.esoc.esa.int/dmsf/files/6/view /// see also https://opssat1.esoc.esa.int/dmsf/files/6/view
use crate::requests::CompositeRequest; use crate::requests::CompositeRequest;
use derive_new::new; use derive_new::new;
use log::debug; use log::debug;
@ -37,6 +36,7 @@ use serde::{Deserialize, Serialize};
use std::io::Error; use std::io::Error;
use std::process::Command; use std::process::Command;
use std::sync::mpsc; use std::sync::mpsc;
use satrs::pus::action::ActionReplyPus;
const DEFAULT_SINGLE_CAM_PARAMS: CameraPictureParameters = CameraPictureParameters { const DEFAULT_SINGLE_CAM_PARAMS: CameraPictureParameters = CameraPictureParameters {
R: 8, R: 8,
@ -78,6 +78,10 @@ const BALANCED_SINGLE_FLATSAT_CAM_PARAMS: CameraPictureParameters = CameraPictur
W: 1000, W: 1000,
}; };
// TODO copy as action
// TODO ls -l via cfdp
// TODO howto downlink
#[derive(Debug)] #[derive(Debug)]
pub enum CameraActionIds { pub enum CameraActionIds {
DefaultSingle = 1, DefaultSingle = 1,
@ -126,19 +130,36 @@ pub struct CameraPictureParameters {
} }
#[allow(dead_code)] #[allow(dead_code)]
#[derive(new)] #[derive(Debug)]
pub struct IMS100BatchHandler { pub struct IMS100BatchHandler {
id: UniqueApidTargetId, id: UniqueApidTargetId,
// mode_interface: MpscModeLeafInterface, // mode_interface: MpscModeLeafInterface,
composite_request_receiver: mpsc::Receiver<GenericMessage<CompositeRequest>>, composite_request_rx: mpsc::Receiver<GenericMessage<CompositeRequest>>,
// hk_reply_sender: mpsc::Sender<GenericMessage<HkReply>>, // hk_reply_sender: mpsc::Sender<GenericMessage<HkReply>>,
tm_sender: mpsc::Sender<PacketAsVec>, tm_tx: mpsc::Sender<PacketAsVec>,
action_reply_tx: mpsc::Sender<GenericMessage<ActionReplyPus>>,
stamp_helper: TimeStampHelper, stamp_helper: TimeStampHelper,
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[allow(dead_code)] #[allow(dead_code)]
impl IMS100BatchHandler { impl IMS100BatchHandler {
pub fn new(
id: UniqueApidTargetId,
composite_request_rx: mpsc::Receiver<GenericMessage<CompositeRequest>>,
tm_tx: mpsc::Sender<PacketAsVec>,
action_reply_tx: mpsc::Sender<GenericMessage<ActionReplyPus>>,
stamp_helper: TimeStampHelper,
) -> Self {
Self {
id,
composite_request_rx,
tm_tx,
action_reply_tx,
stamp_helper,
}
}
pub fn periodic_operation(&mut self) { pub fn periodic_operation(&mut self) {
self.stamp_helper.update_from_now(); self.stamp_helper.update_from_now();
// Handle requests. // Handle requests.
@ -148,13 +169,13 @@ impl IMS100BatchHandler {
pub fn handle_composite_requests(&mut self) { pub fn handle_composite_requests(&mut self) {
loop { loop {
match self.composite_request_receiver.try_recv() { match self.composite_request_rx.try_recv() {
Ok(ref msg) => match &msg.message { Ok(ref msg) => match &msg.message {
CompositeRequest::Hk(hk_request) => { CompositeRequest::Hk(hk_request) => {
self.handle_hk_request(&msg.requestor_info, hk_request); self.handle_hk_request(&msg.requestor_info, hk_request);
} }
CompositeRequest::Action(action_request) => { CompositeRequest::Action(action_request) => {
self.handle_action_request(&msg.requestor_info, action_request); self.handle_action_request(&msg.requestor_info, action_request).unwrap();
} }
}, },
Err(_) => {} Err(_) => {}
@ -236,6 +257,21 @@ impl IMS100BatchHandler {
Ok(()) Ok(())
} }
pub fn list_current_images(&self) -> std::io::Result<Vec<String>> {
let output = Command::new("ls").arg("-l")
.arg("*.png")
.output()?;
if output.status.success() {
let output_str = String::from_utf8(output.stdout).unwrap();
let files: Vec<String> = output_str.lines().map(|s| s.to_string()).collect();
Ok(files)
}
else {
Err(Error::other("Error getting file list."))
}
}
pub fn take_picture_from_str( pub fn take_picture_from_str(
&mut self, &mut self,
R: &str, R: &str,
@ -277,34 +313,40 @@ impl IMS100BatchHandler {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::handlers::camera::{
CameraActionIds, CameraPictureParameters, IMS100BatchHandler,
DEFAULT_SINGLE_FLATSAT_CAM_PARAMS,
};
use crate::requests::CompositeRequest;
use ops_sat_rs::config::components::CAMERA_HANDLER;
use ops_sat_rs::TimeStampHelper;
use satrs::action::{ActionRequest, ActionRequestVariant};
use satrs::request::{GenericMessage, MessageMetadata};
use satrs::tmtc::PacketAsVec;
use std::sync::mpsc; use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender}; use std::sync::mpsc::{Receiver, Sender};
use satrs::action::{ActionRequest, ActionRequestVariant}; use satrs::pus::action::ActionReplyPus;
use satrs::request::{GenericMessage, MessageMetadata, UniqueApidTargetId};
use satrs::tmtc::PacketAsVec;
use ops_sat_rs::TimeStampHelper;
use crate::handlers::camera::{CameraActionIds, CameraPictureParameters, DEFAULT_SINGLE_FLATSAT_CAM_PARAMS, IMS100BatchHandler};
use crate::requests::CompositeRequest;
fn create_handler() -> (IMS100BatchHandler, Sender<GenericMessage<CompositeRequest>>, Receiver<PacketAsVec>) { fn create_handler() -> (IMS100BatchHandler, Sender<GenericMessage<CompositeRequest>>, Receiver<PacketAsVec>, Receiver<GenericMessage<ActionReplyPus>>) {
let id = UniqueApidTargetId::new(1,1); let (composite_request_tx, composite_request_rx) = mpsc::channel();
let (req_tx,req_rx) = mpsc::channel();
let (tm_tx, tm_rx) = mpsc::channel(); let (tm_tx, tm_rx) = mpsc::channel();
let (action_reply_tx, action_reply_rx) = mpsc::channel();
let time_helper = TimeStampHelper::default(); let time_helper = TimeStampHelper::default();
let mut cam_handler: IMS100BatchHandler = IMS100BatchHandler::new(id, req_rx, tm_tx, time_helper); let cam_handler: IMS100BatchHandler =
(cam_handler, req_tx, tm_rx) IMS100BatchHandler::new(CAMERA_HANDLER, composite_request_rx, tm_tx, action_reply_tx, time_helper);
(cam_handler, composite_request_tx, tm_rx, action_reply_rx)
} }
#[test] #[test]
fn command_line_execution() { fn command_line_execution() {
let (mut cam_handler, mut req_tx, mut tm_rx) = create_handler(); let (mut cam_handler, req_tx, tm_rx, action_reply_rx) = create_handler();
cam_handler.take_picture(DEFAULT_SINGLE_FLATSAT_CAM_PARAMS).unwrap(); cam_handler
.take_picture(DEFAULT_SINGLE_FLATSAT_CAM_PARAMS)
.unwrap();
} }
#[test] #[test]
fn serialize_and_deserialize_command() { fn serialize_and_deserialize_command() {
let (mut cam_handler, mut req_tx, mut tm_rx) = create_handler();
let data = serde_json::to_string(&DEFAULT_SINGLE_FLATSAT_CAM_PARAMS).unwrap(); let data = serde_json::to_string(&DEFAULT_SINGLE_FLATSAT_CAM_PARAMS).unwrap();
println!("{}", data); println!("{}", data);
let param: CameraPictureParameters = serde_json::from_str(&data).unwrap(); let param: CameraPictureParameters = serde_json::from_str(&data).unwrap();
@ -313,23 +355,33 @@ mod tests {
#[test] #[test]
fn test_action_req() { fn test_action_req() {
let (mut cam_handler, mut req_tx, mut tm_rx) = create_handler(); let (mut cam_handler, req_tx, tm_rx, action_reply_rx) = create_handler();
let data = serde_json::to_string(&DEFAULT_SINGLE_FLATSAT_CAM_PARAMS).unwrap(); let data = serde_json::to_string(&DEFAULT_SINGLE_FLATSAT_CAM_PARAMS).unwrap();
let req = ActionRequest::new(CameraActionIds::CustomParameters as u32, ActionRequestVariant::VecData(data.as_bytes().to_vec())); let req = ActionRequest::new(
CameraActionIds::CustomParameters as u32,
ActionRequestVariant::VecData(data.as_bytes().to_vec()),
);
cam_handler.handle_action_request(&MessageMetadata::new(1,1),&req).unwrap(); cam_handler
.handle_action_request(&MessageMetadata::new(1, 1), &req)
.unwrap();
} }
#[test] #[test]
fn test_action_req_channel() { fn test_action_req_channel() {
let (mut cam_handler, mut req_tx, mut tm_rx) = create_handler(); let (mut cam_handler, req_tx, tm_rx, action_reply_rx) = create_handler();
let data = serde_json::to_string(&DEFAULT_SINGLE_FLATSAT_CAM_PARAMS).unwrap(); let data = serde_json::to_string(&DEFAULT_SINGLE_FLATSAT_CAM_PARAMS).unwrap();
let req = ActionRequest::new(CameraActionIds::CustomParameters as u32, ActionRequestVariant::VecData(data.as_bytes().to_vec())); let req = ActionRequest::new(
CameraActionIds::CustomParameters as u32,
ActionRequestVariant::VecData(data.as_bytes().to_vec()),
);
let req = CompositeRequest::Action(req); let req = CompositeRequest::Action(req);
req_tx.send(GenericMessage::new(MessageMetadata::new(1,1), req)).unwrap(); req_tx
.send(GenericMessage::new(MessageMetadata::new(1, 1), req))
.unwrap();
cam_handler.periodic_operation(); cam_handler.periodic_operation();
} }
} }

View File

@ -3,6 +3,7 @@ use satrs::spacepackets::time::TimeWriter;
pub mod config; pub mod config;
#[derive(Debug)]
pub struct TimeStampHelper { pub struct TimeStampHelper {
stamper: CdsTime, stamper: CdsTime,
time_stamp: [u8; 7], time_stamp: [u8; 7],

View File

@ -6,6 +6,7 @@ use std::{
}; };
use log::info; use log::info;
use ops_sat_rs::config::components::CAMERA_HANDLER;
use ops_sat_rs::config::{ use ops_sat_rs::config::{
components::{CONTROLLER_ID, TCP_SERVER, TCP_SPP_CLIENT, UDP_SERVER}, components::{CONTROLLER_ID, TCP_SERVER, TCP_SPP_CLIENT, UDP_SERVER},
tasks::{FREQ_MS_CTRL, FREQ_MS_PUS_STACK}, tasks::{FREQ_MS_CTRL, FREQ_MS_PUS_STACK},
@ -13,7 +14,9 @@ use ops_sat_rs::config::{
}; };
use ops_sat_rs::config::{tasks::FREQ_MS_UDP_TMTC, OBSW_SERVER_ADDR, SERVER_PORT}; use ops_sat_rs::config::{tasks::FREQ_MS_UDP_TMTC, OBSW_SERVER_ADDR, SERVER_PORT};
use satrs::hal::std::{tcp_server::ServerConfig, udp_server::UdpTcServer}; use satrs::hal::std::{tcp_server::ServerConfig, udp_server::UdpTcServer};
use ops_sat_rs::TimeStampHelper;
use crate::handlers::camera::IMS100BatchHandler;
use crate::tmtc::tc_source::TcSourceTaskDynamic; use crate::tmtc::tc_source::TcSourceTaskDynamic;
use crate::tmtc::tm_sink::TmFunnelDynamic; use crate::tmtc::tm_sink::TmFunnelDynamic;
use crate::{controller::ExperimentController, pus::test::create_test_service}; use crate::{controller::ExperimentController, pus::test::create_test_service};
@ -62,12 +65,16 @@ fn main() {
// let (pus_mode_reply_tx, pus_mode_reply_rx) = mpsc::channel(); // let (pus_mode_reply_tx, pus_mode_reply_rx) = mpsc::channel();
let (controller_composite_tx, controller_composite_rx) = mpsc::channel(); let (controller_composite_tx, controller_composite_rx) = mpsc::channel();
// let (controller_action_reply_tx, controller_action_reply_rx) = mpsc::channel(); // let (controller_action_reply_tx, controller_action_reply_rx) = mpsc::channel();
let (camera_composite_tx, camera_composite_rx) = mpsc::channel();
// Some request are targetable. This map is used to retrieve sender handles based on a target ID. // Some request are targetable. This map is used to retrieve sender handles based on a target ID.
let mut request_map = GenericRequestRouter::default(); let mut request_map = GenericRequestRouter::default();
request_map request_map
.composite_router_map .composite_router_map
.insert(CONTROLLER_ID.id(), controller_composite_tx); .insert(CONTROLLER_ID.id(), controller_composite_tx);
request_map
.composite_router_map
.insert(CAMERA_HANDLER.id(), camera_composite_tx);
let pus_router = PusTcMpscRouter { let pus_router = PusTcMpscRouter {
test_tc_sender: pus_test_tx, test_tc_sender: pus_test_tx,
@ -161,7 +168,7 @@ fn main() {
let mut controller = ExperimentController::new( let mut controller = ExperimentController::new(
controller_composite_rx, controller_composite_rx,
pus_action_reply_tx, pus_action_reply_tx.clone(),
stop_signal.clone(), stop_signal.clone(),
); );
@ -173,6 +180,13 @@ fn main() {
) )
.expect("creating TCP SPP client failed"); .expect("creating TCP SPP client failed");
let timestamp_helper = TimeStampHelper::default();
let mut camera_handler: IMS100BatchHandler =
IMS100BatchHandler::new(CAMERA_HANDLER, camera_composite_rx, tm_funnel_tx.clone(), pus_action_reply_tx.clone(), timestamp_helper);
// Main Task Thread Definitions
// Main Experiment Control Task
info!("Starting CTRL task"); info!("Starting CTRL task");
let ctrl_stop_signal = stop_signal.clone(); let ctrl_stop_signal = stop_signal.clone();
let jh_ctrl_thread = thread::Builder::new() let jh_ctrl_thread = thread::Builder::new()
@ -186,6 +200,7 @@ fn main() {
}) })
.unwrap(); .unwrap();
// TMTC and UDP Task
info!("Starting TMTC and UDP task"); info!("Starting TMTC and UDP task");
let tmtc_stop_signal = stop_signal.clone(); let tmtc_stop_signal = stop_signal.clone();
let jh_udp_tmtc = thread::Builder::new() let jh_udp_tmtc = thread::Builder::new()
@ -203,6 +218,7 @@ fn main() {
}) })
.unwrap(); .unwrap();
// TCP Server Task
let tcp_server_stop_signal = stop_signal.clone(); let tcp_server_stop_signal = stop_signal.clone();
info!("Starting TCP server task"); info!("Starting TCP server task");
let jh_tcp_server = thread::Builder::new() let jh_tcp_server = thread::Builder::new()
@ -218,6 +234,7 @@ fn main() {
}) })
.unwrap(); .unwrap();
// TCP SPP Client Task
// We could also move this to the existing TCP server thread, but we would have to adapt // We could also move this to the existing TCP server thread, but we would have to adapt
// the server code for this so we do not block anymore and we pause manually if both the client // the server code for this so we do not block anymore and we pause manually if both the client
// and server are IDLE and have nothing to do.. // and server are IDLE and have nothing to do..
@ -236,6 +253,7 @@ fn main() {
}) })
.unwrap(); .unwrap();
// TM Funnel Task
info!("Starting TM funnel task"); info!("Starting TM funnel task");
let funnel_stop_signal = stop_signal.clone(); let funnel_stop_signal = stop_signal.clone();
let jh_tm_funnel = thread::Builder::new() let jh_tm_funnel = thread::Builder::new()
@ -248,7 +266,8 @@ fn main() {
}) })
.unwrap(); .unwrap();
info!("Starting PUS handlers thread"); // PUS Handler Task
info!("Starting PUS handlers task");
let pus_stop_signal = stop_signal.clone(); let pus_stop_signal = stop_signal.clone();
let jh_pus_handler = thread::Builder::new() let jh_pus_handler = thread::Builder::new()
.name("ops-sat pus".to_string()) .name("ops-sat pus".to_string())
@ -261,6 +280,20 @@ fn main() {
}) })
.unwrap(); .unwrap();
// Camera Handler Task
info!("Starting camera handler task");
let camera_stop_signal = stop_signal.clone();
let jh_camera_handler = thread::Builder::new()
.name("ops-sat camera".to_string())
.spawn(move || loop {
camera_handler.periodic_operation();
if camera_stop_signal.load(std::sync::atomic::Ordering::Relaxed) {
break;
}
})
.unwrap();
// Join Threads
jh_ctrl_thread jh_ctrl_thread
.join() .join()
.expect("Joining Controller thread failed"); .expect("Joining Controller thread failed");
@ -279,4 +312,7 @@ fn main() {
jh_pus_handler jh_pus_handler
.join() .join()
.expect("Joining PUS handlers thread failed"); .expect("Joining PUS handlers thread failed");
jh_camera_handler
.join()
.expect("Joining camera handler thread failed");
} }

View File

@ -275,8 +275,8 @@ mod tests {
use satrs::pus::test_util::{ use satrs::pus::test_util::{
TEST_APID, TEST_COMPONENT_ID_0, TEST_COMPONENT_ID_1, TEST_UNIQUE_ID_0, TEST_UNIQUE_ID_1, TEST_APID, TEST_COMPONENT_ID_0, TEST_COMPONENT_ID_1, TEST_UNIQUE_ID_0, TEST_UNIQUE_ID_1,
}; };
use satrs::pus::{TcInMemory, verification};
use satrs::pus::verification::test_util::TestVerificationReporter; use satrs::pus::verification::test_util::TestVerificationReporter;
use satrs::pus::{verification, TcInMemory};
use satrs::request::MessageMetadata; use satrs::request::MessageMetadata;
use satrs::ComponentId; use satrs::ComponentId;
use satrs::{ use satrs::{
@ -429,7 +429,13 @@ mod tests {
.verif_reporter() .verif_reporter()
.check_next_is_acceptance_success(id, accepted_token.request_id()); .check_next_is_acceptance_success(id, accepted_token.request_id());
self.pus_packet_tx self.pus_packet_tx
.send(EcssTcAndToken::new(TcInMemory::Vec(PacketAsVec::new(self.service.service_helper.id(), tc.to_vec().unwrap().into())), accepted_token)) .send(EcssTcAndToken::new(
TcInMemory::Vec(PacketAsVec::new(
self.service.service_helper.id(),
tc.to_vec().unwrap().into(),
)),
accepted_token,
))
.unwrap(); .unwrap();
} }
} }
@ -713,4 +719,4 @@ mod tests {
tmtc_err::REQUEST_TIMEOUT.raw() as u64, tmtc_err::REQUEST_TIMEOUT.raw() as u64,
); );
} }
} }