Skip to content

Commit

Permalink
continue PCDU
Browse files Browse the repository at this point in the history
  • Loading branch information
robamu committed May 18, 2024
1 parent 3db54da commit cb0a65c
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 59 deletions.
8 changes: 8 additions & 0 deletions satrs-example/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ pub mod components {
Acs = 3,
Cfdp = 4,
Tmtc = 5,
Eps = 6,
}

// Component IDs for components with the PUS APID.
Expand All @@ -150,6 +151,11 @@ pub mod components {
Mgm0 = 0,
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum EpsId {
Pcdu = 0,
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum TmtcId {
UdpServer = 0,
Expand All @@ -172,6 +178,8 @@ pub mod components {
UniqueApidTargetId::new(Apid::Sched as u16, 0);
pub const MGM_HANDLER_0: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Acs as u16, AcsId::Mgm0 as u32);
pub const PCDU_HANDLER: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Eps as u16, EpsId::Pcdu as u32);
pub const UDP_SERVER: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Tmtc as u16, TmtcId::UdpServer as u32);
pub const TCP_SERVER: UniqueApidTargetId =
Expand Down
120 changes: 105 additions & 15 deletions satrs-example/src/eps/pcdu.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
use std::{
collections::HashMap,
cell::RefCell,
collections::VecDeque,
sync::{mpsc, Arc, Mutex},
};

use derive_new::new;
use satrs::{
hk::{HkRequest, HkRequestVariant},
mode::{ModeAndSubmode, ModeError, ModeProvider, ModeReply, ModeRequestHandler},
power::SwitchState,
power::{SwitchState, SwitchStateBinary},
pus::EcssTmSender,
queue::{GenericSendError, GenericTargetedMessagingError},
request::{GenericMessage, MessageMetadata, UniqueApidTargetId},
};
use satrs_example::{config::components::PUS_MODE_SERVICE, DeviceMode, TimestampHelper};
use satrs_minisim::{SimReply, SimRequest};
use satrs_minisim::{
eps::{PcduReply, PcduRequest, SwitchMap, SwitchMapWrapper},
SerializableSimMsgPayload, SimReply, SimRequest,
};

use crate::{acs::mgm::MpscModeLeafInterface, pus::hk::HkReply, requests::CompositeRequest};

Expand All @@ -29,12 +33,13 @@ pub trait SerialInterface {
) -> Result<(), Self::Error>;
}

pub struct SimSerialInterface {
#[derive(new)]
pub struct SerialInterfaceToSim {
pub sim_request_tx: mpsc::Sender<SimRequest>,
pub sim_reply_rx: mpsc::Receiver<SimReply>,
}

impl SerialInterface for SimSerialInterface {
impl SerialInterface for SerialInterfaceToSim {
type Error = ();

fn send(&self, data: &[u8]) -> Result<(), Self::Error> {
Expand Down Expand Up @@ -68,27 +73,112 @@ impl SerialInterface for SimSerialInterface {
}
}

#[derive(Default)]
pub struct SerialInterfaceDummy {
// Need interior mutability here for both fields.
pub switch_map: RefCell<SwitchMapWrapper>,
pub reply_deque: RefCell<VecDeque<SimReply>>,
}

impl SerialInterface for SerialInterfaceDummy {
type Error = ();

fn send(&self, data: &[u8]) -> Result<(), Self::Error> {
let sim_req: SimRequest = serde_json::from_slice(data).unwrap();
let pcdu_req =
PcduRequest::from_sim_message(&sim_req).expect("PCDU request creation failed");
let switch_map_mut = &mut self.switch_map.borrow_mut().0;
match pcdu_req {
PcduRequest::SwitchDevice { switch, state } => {
match switch_map_mut.entry(switch) {
std::collections::hash_map::Entry::Occupied(mut val) => {
match state {
SwitchStateBinary::Off => {
*val.get_mut() = SwitchState::Off;
}
SwitchStateBinary::On => {
*val.get_mut() = SwitchState::On;
}
};
}
std::collections::hash_map::Entry::Vacant(vacant) => {
match state {
SwitchStateBinary::Off => vacant.insert(SwitchState::Off),
SwitchStateBinary::On => vacant.insert(SwitchState::On),
};
}
};
}
PcduRequest::RequestSwitchInfo => {
let mut reply_deque_mut = self.reply_deque.borrow_mut();
reply_deque_mut.push_back(SimReply::new(&PcduReply::SwitchInfo(
self.switch_map.borrow().0.clone(),
)));
}
};
Ok(())
}

fn try_recv_replies<ReplyHandler: FnMut(&[u8])>(
&self,
mut f: ReplyHandler,
) -> Result<(), Self::Error> {
if self.reply_deque.borrow().is_empty() {
return Ok(());
}
loop {
let mut reply_deque_mut = self.reply_deque.borrow_mut();
let next_reply = reply_deque_mut.pop_front().unwrap();
let reply = serde_json::to_string(&next_reply).unwrap();
f(reply.as_bytes());
if reply_deque_mut.is_empty() {
break;
}
}
Ok(())
}
}

pub enum SerialSimInterfaceWrapper {
Dummy(SerialInterfaceDummy),
Sim(SerialInterfaceToSim),
}

impl SerialInterface for SerialSimInterfaceWrapper {
type Error = ();

fn send(&self, data: &[u8]) -> Result<(), Self::Error> {
match self {
SerialSimInterfaceWrapper::Dummy(dummy) => dummy.send(data),
SerialSimInterfaceWrapper::Sim(sim) => sim.send(data),
}
}

fn try_recv_replies<ReplyHandler: FnMut(&[u8])>(
&self,
f: ReplyHandler,
) -> Result<(), Self::Error> {
match self {
SerialSimInterfaceWrapper::Dummy(dummy) => dummy.try_recv_replies(f),
SerialSimInterfaceWrapper::Sim(sim) => sim.try_recv_replies(f),
}
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum OpCode {
RegularOp = 0,
PollAndRecvReplies = 1,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum SwitchId {
Mgm0 = 0,
Mgt = 1,
}

pub type SwitchMap = HashMap<SwitchId, SwitchState>;

#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, Default)]
pub struct SwitchSet {
pub valid: bool,
pub switch_map: SwitchMap,
}

pub type SharedSwitchSet = Arc<Mutex<SwitchSet>>;

/// Example PCDU device handler.
#[derive(new)]
#[allow(clippy::too_many_arguments)]
Expand Down
72 changes: 66 additions & 6 deletions satrs-example/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ mod pus;
mod requests;
mod tmtc;

use crate::eps::pcdu::{
PcduHandler, SerialInterfaceDummy, SerialInterfaceToSim, SerialSimInterfaceWrapper,
};
use crate::events::EventHandler;
use crate::interface::udp::DynamicUdpTmHandler;
use crate::pus::stack::PusStack;
Expand Down Expand Up @@ -45,7 +48,7 @@ use crate::requests::{CompositeRequest, GenericRequestRouter};
use satrs::mode::ModeRequest;
use satrs::pus::event_man::EventRequestWithToken;
use satrs::spacepackets::{time::cds::CdsTime, time::TimeWriter};
use satrs_example::config::components::{MGM_HANDLER_0, TCP_SERVER, UDP_SERVER};
use satrs_example::config::components::{MGM_HANDLER_0, PCDU_HANDLER, TCP_SERVER, UDP_SERVER};
use std::net::{IpAddr, SocketAddr};
use std::sync::mpsc;
use std::sync::{Arc, RwLock};
Expand All @@ -68,11 +71,17 @@ fn static_tmtc_pool_main() {

let (sim_request_tx, sim_request_rx) = mpsc::channel();
let (mgm_sim_reply_tx, mgm_sim_reply_rx) = mpsc::channel();
let (pcdu_sim_reply_tx, pcdu_sim_reply_rx) = mpsc::channel();
let mut opt_sim_client = create_sim_client(sim_request_rx);

let (mgm_handler_composite_tx, mgm_handler_composite_rx) =
mpsc::channel::<GenericMessage<CompositeRequest>>();
let (pcdu_handler_composite_tx, pcdu_handler_composite_rx) =
mpsc::channel::<GenericMessage<CompositeRequest>>();

let (mgm_handler_mode_tx, mgm_handler_mode_rx) = mpsc::channel::<GenericMessage<ModeRequest>>();
let (pcdu_handler_mode_tx, pcdu_handler_mode_rx) =
mpsc::channel::<GenericMessage<ModeRequest>>();

// Some request are targetable. This map is used to retrieve sender handles based on a target ID.
let mut request_map = GenericRequestRouter::default();
Expand All @@ -82,6 +91,12 @@ fn static_tmtc_pool_main() {
request_map
.mode_router_map
.insert(MGM_HANDLER_0.id(), mgm_handler_mode_tx);
request_map
.composite_router_map
.insert(PCDU_HANDLER.id(), pcdu_handler_composite_tx);
request_map
.mode_router_map
.insert(PCDU_HANDLER.id(), pcdu_handler_mode_tx);

// This helper structure is used by all telecommand providers which need to send telecommands
// to the TC source.
Expand Down Expand Up @@ -207,10 +222,11 @@ fn static_tmtc_pool_main() {
let (mgm_handler_mode_reply_to_parent_tx, _mgm_handler_mode_reply_to_parent_rx) =
mpsc::channel();

let shared_switch_set = Arc::default();
let shared_mgm_set = Arc::default();
let mode_leaf_interface = MpscModeLeafInterface {
let mgm_mode_leaf_interface = MpscModeLeafInterface {
request_rx: mgm_handler_mode_rx,
reply_to_pus_tx: pus_mode_reply_tx,
reply_to_pus_tx: pus_mode_reply_tx.clone(),
reply_to_parent_tx: mgm_handler_mode_reply_to_parent_tx,
};

Expand All @@ -226,14 +242,41 @@ fn static_tmtc_pool_main() {
let mut mgm_handler = MgmHandlerLis3Mdl::new(
MGM_HANDLER_0,
"MGM_0",
mode_leaf_interface,
mgm_mode_leaf_interface,
mgm_handler_composite_rx,
pus_hk_reply_tx,
tm_sink_tx,
pus_hk_reply_tx.clone(),
tm_sink_tx.clone(),
mgm_spi_interface,
shared_mgm_set,
);

let (pcdu_handler_mode_reply_to_parent_tx, _pcdu_handler_mode_reply_to_parent_rx) =
mpsc::channel();
let pcdu_mode_leaf_interface = MpscModeLeafInterface {
request_rx: pcdu_handler_mode_rx,
reply_to_pus_tx: pus_mode_reply_tx,
reply_to_parent_tx: pcdu_handler_mode_reply_to_parent_tx,
};
let pcdu_serial_interface = if let Some(sim_client) = opt_sim_client.as_mut() {
sim_client.add_reply_recipient(satrs_minisim::SimComponent::Pcdu, pcdu_sim_reply_tx);
SerialSimInterfaceWrapper::Sim(SerialInterfaceToSim::new(
sim_request_tx.clone(),
pcdu_sim_reply_rx,
))
} else {
SerialSimInterfaceWrapper::Dummy(SerialInterfaceDummy::default())
};
let mut pcdu_handler = PcduHandler::new(
PCDU_HANDLER,
"PCDU",
pcdu_mode_leaf_interface,
pcdu_handler_composite_rx,
pus_hk_reply_tx,
tm_sink_tx,
pcdu_serial_interface,
shared_switch_set,
);

info!("Starting TMTC and UDP task");
let jh_udp_tmtc = thread::Builder::new()
.name("SATRS tmtc-udp".to_string())
Expand Down Expand Up @@ -290,6 +333,21 @@ fn static_tmtc_pool_main() {
})
.unwrap();

info!("Starting EPS thread");
let jh_eps = thread::Builder::new()
.name("sat-rs eps".to_string())
.spawn(move || loop {
// TODO: We should introduce something like a fixed timeslot helper to allow a more
// declarative API. It would also be very useful for the AOCS task.
pcdu_handler.periodic_operation(eps::pcdu::OpCode::RegularOp);
thread::sleep(Duration::from_millis(50));
pcdu_handler.periodic_operation(eps::pcdu::OpCode::PollAndRecvReplies);
thread::sleep(Duration::from_millis(50));
pcdu_handler.periodic_operation(eps::pcdu::OpCode::PollAndRecvReplies);
thread::sleep(Duration::from_millis(300));
})
.unwrap();

info!("Starting PUS handler thread");
let jh_pus_handler = thread::Builder::new()
.name("sat-rs pus".to_string())
Expand All @@ -315,6 +373,7 @@ fn static_tmtc_pool_main() {
.expect("Joining SIM client thread failed");
}
jh_aocs.join().expect("Joining AOCS thread failed");
jh_eps.join().expect("Joining EPS thread failed");
jh_pus_handler
.join()
.expect("Joining PUS handler thread failed");
Expand All @@ -328,6 +387,7 @@ fn dyn_tmtc_pool_main() {

let (sim_request_tx, sim_request_rx) = mpsc::channel();
let (mgm_sim_reply_tx, mgm_sim_reply_rx) = mpsc::channel();
// let (pcdu_sim_reply_tx, pcdu_sim_reply_rx) = mpsc::channel();
let mut opt_sim_client = create_sim_client(sim_request_rx);

// Some request are targetable. This map is used to retrieve sender handles based on a target ID.
Expand Down
1 change: 1 addition & 0 deletions satrs-minisim/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ serde_json = "1"
log = "0.4"
thiserror = "1"
fern = "0.5"
strum = { version = "0.26", features = ["derive"] }
humantime = "2"

[dependencies.asynchronix]
Expand Down
Loading

0 comments on commit cb0a65c

Please sign in to comment.