Compare commits

...

20 Commits

Author SHA1 Message Date
6a4417c954 added and scheduled MGM assembly 2025-05-19 16:18:31 +02:00
f600ee499a Merge pull request 'add first generator' (#234) from generators into main
Reviewed-on: #234
2025-05-19 15:23:37 +02:00
3f28f60c59 add first generator 2025-05-19 15:21:51 +02:00
44b1f2b037 Merge pull request 'possible fix for clippy warning' (#233) from possible-fix-for-clippy-warning into main
Reviewed-on: #233
2025-05-19 15:15:24 +02:00
4b22958b34 possible fix for clippy warning 2025-05-19 15:14:59 +02:00
a711c6acd9 Merge pull request 'bump spacepackets' (#232) from bump-spacepackets into main
Reviewed-on: #232
2025-05-19 14:19:00 +02:00
99a954a1f5 some tweaks 2025-05-19 14:18:26 +02:00
4a4fd7ac2c use git deps 2025-05-16 19:49:43 +02:00
9bf08849a2 annoying 2025-05-16 19:43:45 +02:00
b8f7fefe26 Merge pull request 'should fix tests' (#231) from test-fix into main
Reviewed-on: #231
2025-05-10 16:31:14 +02:00
a501832698 should fix tests 2025-05-10 16:30:37 +02:00
c7284d3f1c Merge pull request 'minor wording improvements' (#230) from some-wording-improvements into main
Reviewed-on: #230
2025-05-10 16:27:37 +02:00
18263d4568 Merge branch 'main' into some-wording-improvements 2025-05-10 16:27:29 +02:00
95519c1363 minor wording improvements 2025-05-10 16:27:04 +02:00
2ec32717d0 Merge pull request 'use released dependencies' (#229) from use-relesed-dependencies into main
Reviewed-on: #229
2025-05-10 16:24:37 +02:00
bfdd777685 use released dependencies 2025-05-10 16:24:06 +02:00
b54c2b7863 Merge pull request 'spacepackets update' (#227) from spacepackets-update into main
Reviewed-on: #227
2025-05-10 16:19:07 +02:00
19f3355283 Merge pull request 'update SIM suite name' (#228) from update-sim-suite-name into main
Reviewed-on: #228
2025-05-10 16:18:16 +02:00
4aeb28d2f1 update SIM suite name 2025-05-10 16:14:48 +02:00
ddc4544456 spacepackets update, clippy fixes 2025-05-10 16:13:45 +02:00
48 changed files with 728 additions and 357 deletions

View File

@@ -38,7 +38,7 @@ This project currently contains following crates:
Example of a simple example on-board software using various sat-rs components which can be run
on a host computer or on any system with a standard runtime like a Raspberry Pi.
* [`satrs-minisim`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-minisim):
Mini-Simulator based on [asynchronix](https://github.com/asynchronics/asynchronix) which
Mini-Simulator based on [nexosim](https://github.com/asynchronics/nexosim) which
simulates some physical devices for the `satrs-example` application device handlers.
* [`satrs-mib`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-mib):
Components to build a mission information base from the on-board software directly.

View File

@@ -0,0 +1,8 @@
[package]
name = "satrs-gen"
version = "0.1.0"
edition = "2024"
[dependencies]
toml = "0.8"
heck = "0.5"

View File

@@ -0,0 +1,34 @@
[apid]
Sched = 1
GenericPus = 2
Acs = 3
Cfdp = 4
Tmtc = 5
Eps = 6
[ids]
[ids.Eps]
Pcdu = 0
Subsystem = 1
[ids.Tmtc]
UdpServer = 0
TcpServer = 1
[ids.GenericPus]
PusEventManagement = 0
PusRouting = 1
PusTest = 2
PusAction = 3
PusMode = 4
PusHk = 5
[ids.Sched]
PusSched = 0
[ids.Acs]
Subsystem = 1
Assembly = 2
Mgm0 = 3
Mgm1 = 4

View File

@@ -0,0 +1,91 @@
use heck::{ToShoutySnakeCase, ToSnakeCase};
use std::{
collections::BTreeMap,
fs::{self, File},
io::{self, Write},
};
use toml::{Value, map::Map};
fn main() -> io::Result<()> {
// Read the configuration file
let config_str = fs::read_to_string("components.toml").expect("Unable to read file");
let config: Value = toml::from_str(&config_str).expect("Unable to parse TOML");
let mut output = File::create("../satrs-example/src/ids.rs")?;
generate_rust_code(&config, &mut output);
Ok(())
}
fn sort_enum_table(table_map: &Map<String, Value>) -> BTreeMap<u64, &str> {
// Collect entries into a BTreeMap to sort them by key
let mut sorted_entries: BTreeMap<u64, &str> = BTreeMap::new();
for (key, value) in table_map {
if let Some(value) = value.as_integer() {
if !(0..=0x7FF).contains(&value) {
panic!("Invalid APID value: {}", value);
}
sorted_entries.insert(value as u64, key);
}
}
sorted_entries
}
fn generate_rust_code(config: &Value, writer: &mut impl Write) {
writeln!(
writer,
"//! This is an auto-generated configuration module."
)
.unwrap();
writeln!(writer, "use satrs::request::UniqueApidTargetId;").unwrap();
writeln!(writer).unwrap();
// Generate the main module
writeln!(
writer,
"#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::EnumIter)]"
)
.unwrap();
writeln!(writer, "pub enum Apid {{").unwrap();
// Generate constants for the main module
if let Some(apid_table) = config.get("apid").and_then(Value::as_table) {
let sorted_entries = sort_enum_table(apid_table);
// Write the sorted entries to the writer
for (value, key) in sorted_entries {
writeln!(writer, " {} = {},", key, value).unwrap();
}
}
writeln!(writer, "}}").unwrap();
// Generate ID tables.
if let Some(id_tables) = config.get("ids").and_then(Value::as_table) {
for (mod_name, table) in id_tables {
let mod_name_as_snake = mod_name.to_snake_case();
writeln!(writer).unwrap();
writeln!(writer, "pub mod {} {{", mod_name_as_snake).unwrap();
let sorted_entries = sort_enum_table(table.as_table().unwrap());
writeln!(writer, " #[derive(Debug, Copy, Clone, PartialEq, Eq)]").unwrap();
writeln!(writer, " pub enum Id {{").unwrap();
// Write the sorted entries to the writer
for (value, key) in &sorted_entries {
writeln!(writer, " {} = {},", key, value).unwrap();
}
writeln!(writer, " }}").unwrap();
writeln!(writer).unwrap();
for (_value, key) in sorted_entries {
let key_shouting = key.to_shouty_snake_case();
writeln!(
writer,
" pub const {}: super::UniqueApidTargetId = super::UniqueApidTargetId::new(super::Apid::{} as u16, Id::{} as u32);",
key_shouting, mod_name, key
).unwrap();
}
writeln!(writer, "}}").unwrap();
}
}
}

View File

@@ -1 +1,175 @@
// TODO: Write the assembly
//
use std::sync::mpsc;
use satrs::{
dev_mgmt::{DevManagerCommandingHelper, DevManagerHelperResult, TransparentDevManagerHook},
mode::{
ModeAndSubmode, ModeError, ModeProvider, ModeReply, ModeReplyReceiver as _,
ModeReplySender as _, ModeRequest, ModeRequestHandler, ModeRequestReceiver as _,
ModeRequestorAndHandlerMpscBounded, UNKNOWN_MODE,
},
mode_tree::{ModeChild, ModeNode, ModeParent},
queue::GenericTargetedMessagingError,
request::{GenericMessage, MessageMetadata},
ComponentId,
};
use satrs_example::{ids, DeviceMode};
pub type RequestSenderType = mpsc::SyncSender<GenericMessage<ModeRequest>>;
pub type ReplySenderType = mpsc::SyncSender<GenericMessage<ModeReply>>;
// TODO: Needs to perform same functions as the integration test assembly, but also needs
// to track mode changes and health changes of children.
pub struct MgmAssembly {
pub mode_node: ModeRequestorAndHandlerMpscBounded,
pub mode_requestor_info: Option<MessageMetadata>,
pub mode_and_submode: ModeAndSubmode,
pub commanding_helper: DevManagerCommandingHelper<TransparentDevManagerHook>,
}
impl MgmAssembly {
pub fn new(mode_node: ModeRequestorAndHandlerMpscBounded) -> Self {
Self {
mode_node,
mode_requestor_info: None,
mode_and_submode: UNKNOWN_MODE,
commanding_helper: DevManagerCommandingHelper::new(TransparentDevManagerHook::default()),
}
}
pub const fn id() -> ComponentId {
ids::acs::MGM_ASSEMBLY.raw()
}
pub fn periodic_operation(&mut self) {
self.check_mode_requests().expect("mode messaging error");
self.check_mode_replies().expect("mode messaging error");
// TODO: perform target keeping, check whether children are in correct mode.
}
pub fn check_mode_requests(&mut self) -> Result<(), GenericTargetedMessagingError> {
while let Some(request) = self.mode_node.try_recv_mode_request()? {
self.handle_mode_request(request).unwrap();
}
Ok(())
}
pub fn check_mode_replies(&mut self) -> Result<(), ModeError> {
while let Some(reply_and_id) = self.mode_node.try_recv_mode_reply()? {
match self.commanding_helper.handle_mode_reply(&reply_and_id) {
Ok(result) => {
if let DevManagerHelperResult::ModeCommandingDone(context) = result {
// Complete the mode command.
self.mode_and_submode = context.target_mode;
self.handle_mode_reached(self.mode_requestor_info)?;
}
}
Err(err) => match err {
satrs::dev_mgmt::DevManagerHelperError::ChildNotInStore => todo!(),
},
}
}
Ok(())
}
}
impl ModeNode for MgmAssembly {
fn id(&self) -> ComponentId {
Self::id()
}
}
impl ModeParent for MgmAssembly {
type Sender = RequestSenderType;
fn add_mode_child(&mut self, id: ComponentId, request_sender: RequestSenderType) {
self.mode_node.add_request_target(id, request_sender);
self.commanding_helper.add_mode_child(id, UNKNOWN_MODE);
}
}
impl ModeChild for MgmAssembly {
type Sender = ReplySenderType;
fn add_mode_parent(&mut self, id: ComponentId, reply_sender: ReplySenderType) {
self.mode_node.add_reply_target(id, reply_sender);
}
}
impl ModeProvider for MgmAssembly {
fn mode_and_submode(&self) -> ModeAndSubmode {
self.mode_and_submode
}
}
impl ModeRequestHandler for MgmAssembly {
type Error = ModeError;
fn start_transition(
&mut self,
requestor: MessageMetadata,
mode_and_submode: ModeAndSubmode,
forced: bool,
) -> Result<(), Self::Error> {
// Always accept forced commands and commands to mode OFF.
if self.commanding_helper.target_mode().is_some()
&& !forced
&& mode_and_submode.mode() != DeviceMode::Off as u32
{
return Err(ModeError::Busy);
}
self.mode_requestor_info = Some(requestor);
self.commanding_helper.send_mode_cmd_to_all_children(
requestor.request_id(),
mode_and_submode,
forced,
&self.mode_node,
)?;
Ok(())
}
fn announce_mode(&self, requestor_info: Option<MessageMetadata>, recursive: bool) {
println!(
"TestAssembly: Announcing mode (recursively: {}): {:?}",
recursive, self.mode_and_submode
);
let request_id = requestor_info.map_or(0, |info| info.request_id());
self.commanding_helper
.send_announce_mode_cmd_to_children(request_id, &self.mode_node, recursive)
.expect("sending mode request failed");
// TODO: Send announce event.
log::info!(
"MGM assembly announcing mode: {:?}",
self.mode_and_submode()
);
}
fn handle_mode_reached(
&mut self,
mode_requestor: Option<MessageMetadata>,
) -> Result<(), Self::Error> {
if let Some(requestor) = mode_requestor {
self.send_mode_reply(requestor, ModeReply::ModeReply(self.mode_and_submode))?;
}
self.announce_mode(mode_requestor, false);
Ok(())
}
fn handle_mode_info(
&mut self,
requestor_info: MessageMetadata,
info: ModeAndSubmode,
) -> Result<(), Self::Error> {
// TODO: Perform mode keeping.
Ok(())
}
fn send_mode_reply(
&self,
requestor: MessageMetadata,
reply: ModeReply,
) -> Result<(), Self::Error> {
self.mode_node.send_mode_reply(requestor, reply)?;
Ok(())
}
}

View File

@@ -2,7 +2,7 @@ use derive_new::new;
use satrs::hk::{HkRequest, HkRequestVariant};
use satrs::mode_tree::{ModeChild, ModeNode};
use satrs::power::{PowerSwitchInfo, PowerSwitcherCommandSender};
use satrs_example::config::pus::PUS_MODE_SERVICE;
use satrs_example::ids::generic_pus::PUS_MODE;
use satrs_example::{DeviceMode, TimestampHelper};
use satrs_minisim::acs::lis3mdl::{
MgmLis3MdlReply, MgmLis3RawValues, FIELD_LSB_PER_GAUSS_4_SENS, GAUSS_TO_MICROTESLA_FACTOR,
@@ -400,6 +400,7 @@ impl<
}
fn announce_mode(&self, _requestor_info: Option<MessageMetadata>, _recursive: bool) {
// TODO: Event
log::info!(
"{} announcing mode: {:?}",
self.dev_str,
@@ -417,7 +418,7 @@ impl<
if requestor.sender_id() == NO_SENDER {
return Ok(());
}
if requestor.sender_id() != PUS_MODE_SERVICE.id() {
if requestor.sender_id() != PUS_MODE.id() {
log::warn!(
"can not send back mode reply to sender {:x}",
requestor.sender_id()
@@ -434,7 +435,7 @@ impl<
requestor: MessageMetadata,
reply: ModeReply,
) -> Result<(), Self::Error> {
if requestor.sender_id() != PUS_MODE_SERVICE.id() {
if requestor.sender_id() != PUS_MODE.id() {
log::warn!(
"can not send back mode reply to sender {}",
requestor.sender_id()
@@ -492,7 +493,7 @@ mod tests {
tmtc::PacketAsVec,
ComponentId,
};
use satrs_example::config::{acs::MGM_ASSEMBLY, components::Apid};
use satrs_example::ids::{acs::MGM_ASSEMBLY, Apid};
use satrs_minisim::acs::lis3mdl::MgmLis3RawValues;
use crate::{eps::TestSwitchHelper, pus::hk::HkReply, requests::CompositeRequest};
@@ -538,7 +539,7 @@ mod tests {
impl ModeNode for MgmAssemblyMock {
fn id(&self) -> satrs::ComponentId {
PUS_MODE_SERVICE.into()
PUS_MODE.into()
}
}
@@ -557,7 +558,7 @@ mod tests {
impl ModeNode for PusMock {
fn id(&self) -> satrs::ComponentId {
PUS_MODE_SERVICE.into()
PUS_MODE.into()
}
}
@@ -592,7 +593,7 @@ mod tests {
TestSpiInterface::default(),
shared_mgm_set,
);
handler.add_mode_parent(PUS_MODE_SERVICE.into(), reply_tx_to_pus);
handler.add_mode_parent(PUS_MODE.into(), reply_tx_to_pus);
handler.add_mode_parent(MGM_ASSEMBLY.into(), reply_tx_to_parent);
Self {
mode_request_tx: request_tx,
@@ -631,7 +632,7 @@ mod tests {
testbench
.mode_request_tx
.send(GenericMessage::new(
MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
MessageMetadata::new(0, PUS_MODE.id()),
ModeRequest::SetMode {
mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as u32, 0),
forced: false,
@@ -692,7 +693,7 @@ mod tests {
testbench
.mode_request_tx
.send(GenericMessage::new(
MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
MessageMetadata::new(0, PUS_MODE.id()),
ModeRequest::SetMode {
mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as u32, 0),
forced: false,

View File

@@ -1,10 +1,7 @@
use satrs::pus::verification::RequestId;
use satrs::spacepackets::ecss::tc::PusTcCreator;
use satrs::spacepackets::ecss::tm::PusTmReader;
use satrs::{
spacepackets::ecss::{PusPacket, WritablePusPacket},
spacepackets::SpHeader,
};
use satrs::{spacepackets::ecss::PusPacket, spacepackets::SpHeader};
use satrs_example::config::{OBSW_SERVER_ADDR, SERVER_PORT};
use std::net::{IpAddr, SocketAddr, UdpSocket};
use std::time::Duration;
@@ -29,7 +26,7 @@ fn main() {
let res = client.recv(&mut buf);
match res {
Ok(_len) => {
let (pus_tm, size) = PusTmReader::new(&buf, 7).expect("Parsing PUS TM failed");
let pus_tm = PusTmReader::new(&buf, 7).expect("Parsing PUS TM failed");
if pus_tm.service() == 17 && pus_tm.subservice() == 2 {
println!("Received PUS Ping Reply TM[17,2]")
} else if pus_tm.service() == 1 {

View File

@@ -43,14 +43,14 @@ pub const TEST_EVENT: EventU32TypedSev<SeverityInfo> = EventU32TypedSev::<Severi
lazy_static! {
pub static ref PACKET_ID_VALIDATOR: HashSet<PacketId> = {
let mut set = HashSet::new();
for id in components::Apid::iter() {
for id in crate::ids::Apid::iter() {
set.insert(PacketId::new(PacketType::Tc, true, id as u16));
}
set
};
pub static ref APID_VALIDATOR: HashSet<u16> = {
let mut set = HashSet::new();
for id in components::Apid::iter() {
for id in crate::ids::Apid::iter() {
set.insert(id as u16);
}
set
@@ -122,92 +122,11 @@ pub mod mode_err {
}
pub mod components {
use satrs::{request::UniqueApidTargetId, ComponentId};
use strum::EnumIter;
use satrs::ComponentId;
#[derive(Copy, Clone, PartialEq, Eq, EnumIter)]
pub enum Apid {
Sched = 1,
GenericPus = 2,
Acs = 3,
Cfdp = 4,
Tmtc = 5,
Eps = 6,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum EpsId {
Pcdu = 0,
Subsystem = 1,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum TmtcId {
UdpServer = 0,
TcpServer = 1,
}
pub const EPS_SUBSYSTEM: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Eps as u16, EpsId::Subsystem 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 =
UniqueApidTargetId::new(Apid::Tmtc as u16, TmtcId::TcpServer as u32);
pub const NO_SENDER: ComponentId = ComponentId::MAX;
}
pub mod pus {
use super::components::Apid;
use satrs::request::UniqueApidTargetId;
// Component IDs for components with the PUS APID.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum PusId {
PusEventManagement = 0,
PusRouting = 1,
PusTest = 2,
PusAction = 3,
PusMode = 4,
PusHk = 5,
}
pub const PUS_ACTION_SERVICE: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusAction as u32);
pub const PUS_EVENT_MANAGEMENT: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::GenericPus as u16, 0);
pub const PUS_ROUTING_SERVICE: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusRouting as u32);
pub const PUS_TEST_SERVICE: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusTest as u32);
pub const PUS_MODE_SERVICE: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusMode as u32);
pub const PUS_HK_SERVICE: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusHk as u32);
pub const PUS_SCHED_SERVICE: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Sched as u16, 0);
}
pub mod acs {
use super::components::Apid;
use satrs::request::UniqueApidTargetId;
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum AcsId {
Subsystem = 1,
Assembly = 2,
Mgm0 = 3,
Mgm1 = 4,
}
pub const MGM_ASSEMBLY: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Acs as u16, AcsId::Assembly as u32);
pub const MGM_HANDLER_0: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Acs as u16, AcsId::Mgm0 as u32);
pub const MGM_HANDLER_1: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Acs as u16, AcsId::Mgm0 as u32);
}
pub mod pool {
use super::*;
pub fn create_static_pools() -> (StaticMemoryPool, StaticMemoryPool) {

View File

@@ -20,10 +20,8 @@ use satrs::{
spacepackets::ByteConversionError,
};
use satrs_example::{
config::{
components::{NO_SENDER, PCDU_HANDLER},
pus::PUS_MODE_SERVICE,
},
config::components::NO_SENDER,
ids::{eps::PCDU, generic_pus::PUS_MODE},
DeviceMode, TimestampHelper,
};
use satrs_minisim::{
@@ -452,7 +450,7 @@ impl<ComInterface: SerialInterface> ModeRequestHandler for PcduHandler<ComInterf
if requestor.sender_id() == NO_SENDER {
return Ok(());
}
if requestor.sender_id() != PUS_MODE_SERVICE.id() {
if requestor.sender_id() != PUS_MODE.id() {
log::warn!(
"can not send back mode reply to sender {}",
requestor.sender_id()
@@ -469,7 +467,7 @@ impl<ComInterface: SerialInterface> ModeRequestHandler for PcduHandler<ComInterf
requestor: MessageMetadata,
reply: ModeReply,
) -> Result<(), Self::Error> {
if requestor.sender_id() != PUS_MODE_SERVICE.id() {
if requestor.sender_id() != PUS_MODE.id() {
log::warn!(
"can not send back mode reply to sender {}",
requestor.sender_id()
@@ -492,7 +490,7 @@ impl<ComInterface: SerialInterface> ModeRequestHandler for PcduHandler<ComInterf
impl<ComInterface: SerialInterface> ModeNode for PcduHandler<ComInterface> {
fn id(&self) -> satrs::ComponentId {
PCDU_HANDLER.into()
PCDU.into()
}
}
@@ -511,10 +509,7 @@ mod tests {
use satrs::{
mode::ModeRequest, power::SwitchStateBinary, request::GenericMessage, tmtc::PacketAsVec,
};
use satrs_example::config::{
acs::MGM_HANDLER_0,
components::{Apid, EPS_SUBSYSTEM, PCDU_HANDLER},
};
use satrs_example::ids::{self, Apid};
use satrs_minisim::eps::SwitchMapBinary;
use super::*;
@@ -570,8 +565,7 @@ mod tests {
let (mode_request_tx, mode_request_rx) = mpsc::sync_channel(5);
let (mode_reply_tx_to_pus, mode_reply_rx_to_pus) = mpsc::sync_channel(5);
let (mode_reply_tx_to_parent, mode_reply_rx_to_parent) = mpsc::sync_channel(5);
let mode_node =
ModeRequestHandlerMpscBounded::new(PCDU_HANDLER.into(), mode_request_rx);
let mode_node = ModeRequestHandlerMpscBounded::new(PCDU.into(), mode_request_rx);
let (composite_request_tx, composite_request_rx) = mpsc::channel();
let (hk_reply_tx, hk_reply_rx) = mpsc::sync_channel(10);
let (tm_tx, tm_rx) = mpsc::sync_channel::<PacketAsVec>(5);
@@ -588,8 +582,8 @@ mod tests {
SerialInterfaceTest::default(),
shared_switch_map,
);
handler.add_mode_parent(EPS_SUBSYSTEM.into(), mode_reply_tx_to_parent);
handler.add_mode_parent(PUS_MODE_SERVICE.into(), mode_reply_tx_to_pus);
handler.add_mode_parent(ids::eps::SUBSYSTEM.into(), mode_reply_tx_to_parent);
handler.add_mode_parent(PUS_MODE.into(), mode_reply_tx_to_pus);
Self {
mode_request_tx,
mode_reply_rx_to_pus,
@@ -684,7 +678,7 @@ mod tests {
testbench
.mode_request_tx
.send(GenericMessage::new(
MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
MessageMetadata::new(0, PUS_MODE.id()),
ModeRequest::SetMode {
mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as u32, 0),
forced: false,
@@ -719,7 +713,7 @@ mod tests {
testbench
.mode_request_tx
.send(GenericMessage::new(
MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
MessageMetadata::new(0, PUS_MODE.id()),
ModeRequest::SetMode {
mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as u32, 0),
forced: false,
@@ -729,7 +723,7 @@ mod tests {
testbench
.switch_request_tx
.send(GenericMessage::new(
MessageMetadata::new(0, MGM_HANDLER_0.id()),
MessageMetadata::new(0, ids::acs::MGM0.id()),
SwitchRequest::new(0, SwitchStateBinary::On),
))
.expect("failed to send switch request");

View File

@@ -16,7 +16,7 @@ use satrs::{
},
spacepackets::time::cds::CdsTime,
};
use satrs_example::config::pus::PUS_EVENT_MANAGEMENT;
use satrs_example::ids::generic_pus::PUS_EVENT_MANAGEMENT;
use crate::update_time;
@@ -281,9 +281,7 @@ mod tests {
.try_recv()
.expect("failed to receive TM packet");
assert_eq!(tm_packet.sender_id, PUS_EVENT_MANAGEMENT.id());
let tm_reader = PusTmReader::new(&tm_packet.packet, 7)
.expect("failed to create TM reader")
.0;
let tm_reader = PusTmReader::new(&tm_packet.packet, 7).expect("failed to create TM reader");
assert_eq!(tm_reader.apid(), TEST_CREATOR_ID.apid);
assert_eq!(tm_reader.user_data().len(), 4);
let event_read_back = EventU32::from_be_bytes(tm_reader.user_data().try_into().unwrap());

94
satrs-example/src/ids.rs Normal file
View File

@@ -0,0 +1,94 @@
//! This is an auto-generated configuration module.
use satrs::request::UniqueApidTargetId;
#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::EnumIter)]
pub enum Apid {
Sched = 1,
GenericPus = 2,
Acs = 3,
Cfdp = 4,
Tmtc = 5,
Eps = 6,
}
pub mod acs {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Id {
Subsystem = 1,
MgmAssembly = 2,
Mgm0 = 3,
Mgm1 = 4,
}
pub const SUBSYSTEM: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::Acs as u16, Id::Subsystem as u32);
pub const MGM_ASSEMBLY: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::Acs as u16, Id::MgmAssembly as u32);
pub const MGM0: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::Acs as u16, Id::Mgm0 as u32);
pub const MGM1: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::Acs as u16, Id::Mgm1 as u32);
}
pub mod eps {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Id {
Pcdu = 0,
Subsystem = 1,
}
pub const PCDU: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::Eps as u16, Id::Pcdu as u32);
pub const SUBSYSTEM: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::Eps as u16, Id::Subsystem as u32);
}
pub mod generic_pus {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Id {
PusEventManagement = 0,
PusRouting = 1,
PusTest = 2,
PusAction = 3,
PusMode = 4,
PusHk = 5,
}
pub const PUS_EVENT_MANAGEMENT: super::UniqueApidTargetId = super::UniqueApidTargetId::new(
super::Apid::GenericPus as u16,
Id::PusEventManagement as u32,
);
pub const PUS_ROUTING: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::GenericPus as u16, Id::PusRouting as u32);
pub const PUS_TEST: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::GenericPus as u16, Id::PusTest as u32);
pub const PUS_ACTION: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::GenericPus as u16, Id::PusAction as u32);
pub const PUS_MODE: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::GenericPus as u16, Id::PusMode as u32);
pub const PUS_HK: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::GenericPus as u16, Id::PusHk as u32);
}
pub mod sched {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Id {
PusSched = 0,
}
pub const PUS_SCHED: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::Sched as u16, Id::PusSched as u32);
}
pub mod tmtc {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Id {
UdpServer = 0,
TcpServer = 1,
}
pub const UDP_SERVER: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::Tmtc as u16, Id::UdpServer as u32);
pub const TCP_SERVER: super::UniqueApidTargetId =
super::UniqueApidTargetId::new(super::Apid::Tmtc as u16, Id::TcpServer as u32);
}

View File

@@ -119,7 +119,8 @@ mod tests {
},
ComponentId,
};
use satrs_example::config::{components, OBSW_SERVER_ADDR};
use satrs_example::config::OBSW_SERVER_ADDR;
use satrs_example::ids;
use crate::tmtc::sender::{MockSender, TmTcSender};
@@ -175,7 +176,7 @@ mod tests {
udp_tc_server,
tm_handler,
};
let sph = SpHeader::new_for_unseg_tc(components::Apid::GenericPus as u16, 0, 0);
let sph = SpHeader::new_for_unseg_tc(ids::Apid::GenericPus as u16, 0, 0);
let ping_tc = PusTcCreator::new_simple(sph, 17, 1, &[], true)
.to_vec()
.unwrap();

View File

@@ -1,6 +1,7 @@
use satrs::spacepackets::time::{cds::CdsTime, TimeWriter};
pub mod config;
pub mod ids;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum DeviceMode {

View File

@@ -5,7 +5,10 @@ use std::{
time::Duration,
};
use acs::mgm::{MgmHandlerLis3Mdl, SpiDummyInterface, SpiSimInterface, SpiSimInterfaceWrapper};
use acs::{
assembly::MgmAssembly,
mgm::{MgmHandlerLis3Mdl, SpiDummyInterface, SpiSimInterface, SpiSimInterfaceWrapper},
};
use eps::{
pcdu::{PcduHandler, SerialInterfaceDummy, SerialInterfaceToSim, SerialSimInterfaceWrapper},
PowerSwitchHelper,
@@ -31,7 +34,10 @@ use pus::{
use requests::GenericRequestRouter;
use satrs::{
hal::std::{tcp_server::ServerConfig, udp_server::UdpTcServer},
mode::{Mode, ModeAndSubmode, ModeRequest, ModeRequestHandlerMpscBounded},
mode::{
Mode, ModeAndSubmode, ModeRequest, ModeRequestHandlerMpscBounded,
ModeRequestorAndHandlerMpscBounded,
},
mode_tree::connect_mode_nodes,
pus::{event_man::EventRequestWithToken, EcssTcInMemConverter, HandlingStatus},
request::{GenericMessage, MessageMetadata},
@@ -39,12 +45,16 @@ use satrs::{
};
use satrs_example::{
config::{
acs::{MGM_HANDLER_0, MGM_HANDLER_1},
components::{NO_SENDER, PCDU_HANDLER, TCP_SERVER, UDP_SERVER},
components::NO_SENDER,
pool::create_sched_tc_pool,
tasks::{FREQ_MS_AOCS, FREQ_MS_PUS_STACK, FREQ_MS_UDP_TMTC, SIM_CLIENT_IDLE_DELAY_MS},
OBSW_SERVER_ADDR, PACKET_ID_VALIDATOR, SERVER_PORT,
},
ids::{
acs::*,
eps::*,
tmtc::{TCP_SERVER, UDP_SERVER},
},
DeviceMode,
};
use tmtc::sender::TmTcSender;
@@ -124,13 +134,13 @@ fn main() {
let mut request_map = GenericRequestRouter::default();
request_map
.composite_router_map
.insert(MGM_HANDLER_0.id(), mgm_0_handler_composite_tx);
.insert(MGM0.id(), mgm_0_handler_composite_tx);
request_map
.composite_router_map
.insert(MGM_HANDLER_0.id(), mgm_1_handler_composite_tx);
.insert(MGM1.id(), mgm_1_handler_composite_tx);
request_map
.composite_router_map
.insert(PCDU_HANDLER.id(), pcdu_handler_composite_tx);
.insert(PCDU.id(), pcdu_handler_composite_tx);
// This helper structure is used by all telecommand providers which need to send telecommands
// to the TC source.
@@ -299,12 +309,19 @@ fn main() {
let (switch_request_tx, switch_request_rx) = mpsc::sync_channel(20);
let switch_helper = PowerSwitchHelper::new(switch_request_tx, shared_switch_set.clone());
let (mgm_assy_mode_req_tx, mgm_assy_mode_req_rx) = mpsc::sync_channel(20);
let (mgm_assy_mode_reply_tx, mgm_assy_mode_reply_rx) = mpsc::sync_channel(20);
let mgm_assembly_mode_node = ModeRequestorAndHandlerMpscBounded::new(
MgmAssembly::id(),
mgm_assy_mode_req_rx,
mgm_assy_mode_reply_rx,
);
let mut mgm_assembly = MgmAssembly::new(mgm_assembly_mode_node);
let shared_mgm_0_set = Arc::default();
let shared_mgm_1_set = Arc::default();
let mgm_0_mode_node =
ModeRequestHandlerMpscBounded::new(MGM_HANDLER_0.into(), mgm_0_handler_mode_rx);
let mgm_1_mode_node =
ModeRequestHandlerMpscBounded::new(MGM_HANDLER_1.into(), mgm_1_handler_mode_rx);
let mgm_0_mode_node = ModeRequestHandlerMpscBounded::new(MGM0.into(), mgm_0_handler_mode_rx);
let mgm_1_mode_node = ModeRequestHandlerMpscBounded::new(MGM1.into(), mgm_1_handler_mode_rx);
let (mgm_0_spi_interface, mgm_1_spi_interface) =
if let Some(sim_client) = opt_sim_client.as_mut() {
sim_client
@@ -328,7 +345,7 @@ fn main() {
)
};
let mut mgm_0_handler = MgmHandlerLis3Mdl::new(
MGM_HANDLER_0,
MGM0,
"MGM_0",
mgm_0_mode_node,
mgm_0_handler_composite_rx,
@@ -339,7 +356,7 @@ fn main() {
shared_mgm_0_set,
);
let mut mgm_1_handler = MgmHandlerLis3Mdl::new(
MGM_HANDLER_1,
MGM1,
"MGM_1",
mgm_1_mode_node,
mgm_1_handler_composite_rx,
@@ -362,6 +379,19 @@ fn main() {
&mut mgm_1_handler,
pus_mode_reply_tx.clone(),
);
// Connect assembly to device handlers.
connect_mode_nodes(
&mut mgm_assembly,
mgm_assy_mode_req_tx.clone(),
&mut mgm_1_handler,
mgm_assy_mode_reply_tx.clone(),
);
connect_mode_nodes(
&mut mgm_assembly,
mgm_assy_mode_req_tx,
&mut mgm_1_handler,
mgm_assy_mode_reply_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);
@@ -372,10 +402,9 @@ fn main() {
} else {
SerialSimInterfaceWrapper::Dummy(SerialInterfaceDummy::default())
};
let pcdu_mode_node =
ModeRequestHandlerMpscBounded::new(PCDU_HANDLER.into(), pcdu_handler_mode_rx);
let pcdu_mode_node = ModeRequestHandlerMpscBounded::new(PCDU.into(), pcdu_handler_mode_rx);
let mut pcdu_handler = PcduHandler::new(
PCDU_HANDLER,
PCDU,
"PCDU",
pcdu_mode_node,
pcdu_handler_composite_rx,
@@ -454,6 +483,7 @@ fn main() {
let jh_aocs = thread::Builder::new()
.name("sat-rs aocs".to_string())
.spawn(move || loop {
mgm_assembly.periodic_operation();
mgm_0_handler.periodic_operation();
mgm_1_handler.periodic_operation();
thread::sleep(Duration::from_millis(FREQ_MS_AOCS));

View File

@@ -16,8 +16,9 @@ use satrs::pus::{
use satrs::request::{GenericMessage, UniqueApidTargetId};
use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::{EcssEnumU16, PusPacket, PusServiceId};
use satrs_example::config::pus::PUS_ACTION_SERVICE;
use satrs_example::config::tmtc_err;
use satrs_example::ids;
use satrs_example::ids::generic_pus::PUS_ACTION;
use std::sync::mpsc;
use std::time::Duration;
@@ -214,10 +215,10 @@ pub fn create_action_service(
) -> ActionServiceWrapper {
let action_request_handler = PusTargetedRequestService::new(
PusServiceHelper::new(
PUS_ACTION_SERVICE.id(),
ids::generic_pus::PUS_ACTION.id(),
pus_action_rx,
tm_sender,
create_verification_reporter(PUS_ACTION_SERVICE.id(), PUS_ACTION_SERVICE.apid),
create_verification_reporter(PUS_ACTION.id(), PUS_ACTION.apid),
tc_in_mem_converter,
),
ActionRequestConverter::default(),
@@ -367,7 +368,7 @@ mod tests {
if let Err(mpsc::TryRecvError::Empty) = packet {
} else {
let tm = packet.unwrap();
let unexpected_tm = PusTmReader::new(&tm.packet, 7).unwrap().0;
let unexpected_tm = PusTmReader::new(&tm.packet, 7).unwrap();
panic!("unexpected TM packet {unexpected_tm:?}");
}
}
@@ -410,7 +411,11 @@ mod tests {
pub fn add_tc(&mut self, tc: &PusTcCreator) {
self.request_id = Some(verification::RequestId::new(tc).into());
let token = self.service.service_helper.verif_reporter_mut().add_tc(tc);
let token = self
.service
.service_helper
.verif_reporter_mut()
.start_verification(tc);
let accepted_token = self
.service
.service_helper

View File

@@ -10,7 +10,7 @@ use satrs::pus::{
PartialPusHandlingError, PusServiceHelper,
};
use satrs::spacepackets::ecss::PusServiceId;
use satrs_example::config::pus::PUS_EVENT_MANAGEMENT;
use satrs_example::ids::generic_pus::PUS_EVENT_MANAGEMENT;
use super::{DirectPusService, HandlingStatus};

View File

@@ -13,8 +13,8 @@ use satrs::request::{GenericMessage, UniqueApidTargetId};
use satrs::res_code::ResultU16;
use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::{hk, PusPacket, PusServiceId};
use satrs_example::config::pus::PUS_HK_SERVICE;
use satrs_example::config::{hk_err, tmtc_err};
use satrs_example::ids::generic_pus::PUS_HK;
use std::sync::mpsc;
use std::time::Duration;
@@ -249,10 +249,10 @@ pub fn create_hk_service(
) -> HkServiceWrapper {
let pus_3_handler = PusTargetedRequestService::new(
PusServiceHelper::new(
PUS_HK_SERVICE.id(),
PUS_HK.id(),
pus_hk_rx,
tm_sender,
create_verification_reporter(PUS_HK_SERVICE.id(), PUS_HK_SERVICE.apid),
create_verification_reporter(PUS_HK.id(), PUS_HK.apid),
tc_in_mem_converter,
),
HkRequestConverter::default(),

View File

@@ -18,8 +18,8 @@ use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::{PusPacket, PusServiceId};
use satrs::tmtc::{PacketAsVec, PacketInPool};
use satrs::ComponentId;
use satrs_example::config::pus::PUS_ROUTING_SERVICE;
use satrs_example::config::{tmtc_err, CustomPusServiceId};
use satrs_example::ids::generic_pus::PUS_ROUTING;
use satrs_example::TimestampHelper;
use std::fmt::Debug;
use std::sync::mpsc;
@@ -62,12 +62,9 @@ pub struct PusTcDistributor {
impl PusTcDistributor {
pub fn new(tm_sender: TmTcSender, pus_router: PusTcMpscRouter) -> Self {
Self {
id: PUS_ROUTING_SERVICE.raw(),
id: PUS_ROUTING.raw(),
tm_sender,
verif_reporter: create_verification_reporter(
PUS_ROUTING_SERVICE.id(),
PUS_ROUTING_SERVICE.apid,
),
verif_reporter: create_verification_reporter(PUS_ROUTING.id(), PUS_ROUTING.apid),
pus_router,
stamp_helper: TimestampHelper::default(),
}
@@ -109,8 +106,8 @@ impl PusTcDistributor {
// TODO: Shouldn't this be an error?
return Ok(HandlingStatus::HandledOne);
}
let pus_tc = pus_tc_result.unwrap().0;
let init_token = self.verif_reporter.add_tc(&pus_tc);
let pus_tc = pus_tc_result.unwrap();
let init_token = self.verif_reporter.start_verification(&pus_tc);
self.stamp_helper.update_from_now();
let accepted_token = self
.verif_reporter
@@ -599,7 +596,7 @@ pub(crate) mod tests {
) -> (verification::RequestId, ActivePusRequestStd) {
let sp_header = SpHeader::new_from_apid(apid);
let sec_header_dummy = PusTcSecondaryHeader::new_simple(0, 0);
let init = self.verif_reporter.add_tc(&PusTcCreator::new(
let init = self.verif_reporter.start_verification(&PusTcCreator::new(
sp_header,
sec_header_dummy,
&[],
@@ -706,7 +703,7 @@ pub(crate) mod tests {
}
pub fn add_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let token = self.verif_reporter.add_tc(tc);
let token = self.verif_reporter.start_verification(tc);
self.current_request_id = Some(verification::RequestId::new(tc));
self.current_packet = Some(tc.to_vec().unwrap());
self.verif_reporter
@@ -734,7 +731,7 @@ pub(crate) mod tests {
let tc_reader = PusTcReader::new(&current_packet).unwrap();
let (active_info, request) = self.converter.convert(
token,
&tc_reader.0,
&tc_reader,
&self.dummy_sender,
&self.verif_reporter,
time_stamp,

View File

@@ -1,6 +1,6 @@
use derive_new::new;
use satrs::mode_tree::{ModeNode, ModeParent};
use satrs_example::config::pus::PUS_MODE_SERVICE;
use satrs_example::ids;
use std::sync::mpsc;
use std::time::Duration;
@@ -217,15 +217,18 @@ pub fn create_mode_service(
) -> ModeServiceWrapper {
let mode_request_handler = PusTargetedRequestService::new(
PusServiceHelper::new(
PUS_MODE_SERVICE.id(),
ids::generic_pus::PUS_MODE.id(),
pus_action_rx,
tm_sender,
create_verification_reporter(PUS_MODE_SERVICE.id(), PUS_MODE_SERVICE.apid),
create_verification_reporter(
ids::generic_pus::PUS_MODE.id(),
ids::generic_pus::PUS_MODE.apid,
),
tc_in_mem_converter,
),
ModeRequestConverter::default(),
DefaultActiveRequestMap::default(),
ModeReplyHandler::new(PUS_MODE_SERVICE.id()),
ModeReplyHandler::new(ids::generic_pus::PUS_MODE.id()),
mode_router,
reply_receiver,
);

View File

@@ -15,7 +15,7 @@ use satrs::pus::{
use satrs::spacepackets::ecss::PusServiceId;
use satrs::tmtc::{PacketAsVec, PacketInPool, PacketSenderWithSharedPool};
use satrs::ComponentId;
use satrs_example::config::pus::PUS_SCHED_SERVICE;
use satrs_example::ids::sched::PUS_SCHED;
use super::{DirectPusService, HandlingStatus};
@@ -183,10 +183,10 @@ pub fn create_scheduler_service(
.expect("Creating PUS Scheduler failed");
let pus_11_handler = PusSchedServiceHandler::new(
PusServiceHelper::new(
PUS_SCHED_SERVICE.id(),
PUS_SCHED.id(),
pus_sched_rx,
tm_sender,
create_verification_reporter(PUS_SCHED_SERVICE.id(), PUS_SCHED_SERVICE.apid),
create_verification_reporter(PUS_SCHED.id(), PUS_SCHED.apid),
tc_in_mem_converter,
),
scheduler,

View File

@@ -11,8 +11,8 @@ use satrs::pus::{
};
use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::{PusPacket, PusServiceId};
use satrs_example::config::pus::PUS_TEST_SERVICE;
use satrs_example::config::{tmtc_err, TEST_EVENT};
use satrs_example::ids::generic_pus::PUS_TEST;
use std::sync::mpsc;
use super::{DirectPusService, HandlingStatus};
@@ -24,10 +24,10 @@ pub fn create_test_service(
pus_test_rx: mpsc::Receiver<EcssTcAndToken>,
) -> TestCustomServiceWrapper {
let pus17_handler = PusService17TestHandler::new(PusServiceHelper::new(
PUS_TEST_SERVICE.id(),
PUS_TEST.id(),
pus_test_rx,
tm_sender,
create_verification_reporter(PUS_TEST_SERVICE.id(), PUS_TEST_SERVICE.apid),
create_verification_reporter(PUS_TEST.id(), PUS_TEST.apid),
tc_in_mem_converter,
));
TestCustomServiceWrapper {
@@ -90,7 +90,7 @@ impl DirectPusService for TestCustomServiceWrapper {
);
}
DirectPusPacketHandlerResult::CustomSubservice(subservice, token) => {
let (tc, _) = PusTcReader::new(
let tc = PusTcReader::new(
self.handler
.service_helper
.tc_in_mem_converter
@@ -100,7 +100,7 @@ impl DirectPusService for TestCustomServiceWrapper {
if subservice == 128 {
info!("generating test event");
self.event_tx
.send(EventMessage::new(PUS_TEST_SERVICE.id(), TEST_EVENT.into()))
.send(EventMessage::new(PUS_TEST.id(), TEST_EVENT.into()))
.expect("Sending test event failed");
match self.handler.service_helper.verif_reporter().start_success(
self.handler.service_helper.tm_sender(),

View File

@@ -14,8 +14,8 @@ use satrs::request::{GenericMessage, MessageMetadata, UniqueApidTargetId};
use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::PusPacket;
use satrs::ComponentId;
use satrs_example::config::pus::PUS_ROUTING_SERVICE;
use satrs_example::config::tmtc_err;
use satrs_example::ids;
#[derive(Clone, Debug)]
#[non_exhaustive]
@@ -37,7 +37,7 @@ pub struct GenericRequestRouter {
impl Default for GenericRequestRouter {
fn default() -> Self {
Self {
id: PUS_ROUTING_SERVICE.raw(),
id: ids::generic_pus::PUS_ROUTING.raw(),
composite_router_map: Default::default(),
mode_router_map: Default::default(),
}

View File

@@ -11,7 +11,9 @@ use crate::pus::PusTcDistributor;
pub struct TcSourceTaskStatic {
shared_tc_pool: SharedPacketPool,
tc_receiver: mpsc::Receiver<PacketInPool>,
tc_buf: [u8; 4096],
/// We allocate this buffer from the heap to avoid a clippy warning on large enum variant
/// differences.
tc_buf: Box<[u8; 4096]>,
pus_distributor: PusTcDistributor,
}
@@ -25,7 +27,7 @@ impl TcSourceTaskStatic {
Self {
shared_tc_pool,
tc_receiver,
tc_buf: [0; 4096],
tc_buf: Box::new([0; 4096]),
pus_distributor: pus_receiver,
}
}
@@ -44,11 +46,11 @@ impl TcSourceTaskStatic {
.0
.read()
.expect("locking tc pool failed");
pool.read(&packet_in_pool.store_addr, &mut self.tc_buf)
pool.read(&packet_in_pool.store_addr, self.tc_buf.as_mut_slice())
.expect("reading pool failed");
drop(pool);
self.pus_distributor
.handle_tc_packet_in_store(packet_in_pool, &self.tc_buf)
.handle_tc_packet_in_store(packet_in_pool, self.tc_buf.as_slice())
.ok();
HandlingStatus::HandledOne
}

View File

@@ -23,7 +23,8 @@ version = "1"
optional = true
[dependencies.satrs-shared]
version = ">=0.1.3, <=0.2"
version = "0.2.2"
path = "../satrs-shared"
features = ["serde"]
[dependencies.satrs-mib-codegen]

View File

@@ -28,7 +28,8 @@ features = ["full"]
trybuild = { version = "1", features = ["diff"] }
[dev-dependencies.satrs-shared]
version = ">=0.1.3, <=0.2"
version = "0.2.2"
path = "../../satrs-shared"
[dev-dependencies.satrs-mib]
path = ".."

View File

@@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased]
# [v0.2.2] 2025-05-10
- Bump to `spacepackests` v0.14
# [v0.2.1] 2024-11-15
Increased allowed spacepackets to v0.13
@@ -41,3 +45,6 @@ Allow `spacepackets` range starting with v0.10 and v0.11.
# [v0.1.0] 2024-02-12
Initial release.
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/sat-rs/compare/satrs-shared-v0.2.2...HEAD
[v0.2.2]: https://egit.irs.uni-stuttgart.de/rust/sat-rs/compare/satrs-shared-v0.2.1...satrs-shared-v0.2.2

View File

@@ -1,7 +1,7 @@
[package]
name = "satrs-shared"
description = "Components shared by multiple sat-rs crates"
version = "0.2.1"
version = "0.2.2"
edition = "2021"
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
homepage = "https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/"
@@ -11,6 +11,7 @@ license = "Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
spacepackets = { version = ">=0.14, <=0.15", git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git", default-features = false }
[dependencies.serde]
version = "1"
@@ -18,12 +19,9 @@ default-features = false
optional = true
[dependencies.defmt]
version = "0.3"
version = "1"
optional = true
[dependencies.spacepackets]
version = ">0.9, <=0.13"
default-features = false
[features]
serde = ["dep:serde", "spacepackets/serde"]

View File

@@ -4,8 +4,8 @@ version = "0.3.0-alpha.0"
edition = "2021"
rust-version = "1.82.0"
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
description = "A framework to build software for remote systems"
homepage = "https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/"
description = "A library collection to build software for remote systems"
homepage = "https://github.com/us-irs/sat-rs"
repository = "https://egit.irs.uni-stuttgart.de/rust/sat-rs"
license = "Apache-2.0"
keywords = ["no-std", "space", "aerospace"]
@@ -13,16 +13,14 @@ keywords = ["no-std", "space", "aerospace"]
categories = ["aerospace", "aerospace::space-protocols", "no-std", "hardware-support", "embedded"]
[dependencies]
satrs-shared = ">=0.1.3, <=0.2"
satrs-shared = { version = "0.2.2", path = "../satrs-shared" }
spacepackets = { version = ">=0.14, <=0.15", git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git", default-features = false }
delegate = ">0.7, <=0.13"
paste = "1"
derive-new = ">=0.6, <=0.7"
smallvec = "1"
crc = "3"
num_enum = { version = ">0.5, <=0.7", default-features = false }
spacepackets = { version = "0.13", default-features = false }
cobs = { version = "0.3", default-features = false }
num-traits = { version = "0.2", default-features = false }
cobs = { version = "0.4", default-features = false, git = "https://github.com/jamesmunns/cobs.rs.git", branch = "main" }
thiserror = { version = "2", default-features = false }
hashbrown = { version = ">=0.14, <=0.15", optional = true }

View File

@@ -4,5 +4,5 @@
sat-rs
======
This crate contains the primary components of the sat-rs framework.
This crate contains the primary components of the sat-rs library collection.
You can find more information on the [homepage](https://egit.irs.uni-stuttgart.de/rust/sat-rs).

View File

@@ -24,8 +24,8 @@ use cobs::{decode_in_place, encode, max_encoding_length};
/// assert!(encode_packet_with_cobs(&INVERTED_PACKET, &mut encoding_buf, &mut current_idx));
/// assert_eq!(encoding_buf[0], 0);
/// let dec_report = decode_in_place_report(&mut encoding_buf[1..]).expect("decoding failed");
/// assert_eq!(encoding_buf[1 + dec_report.src_used], 0);
/// assert_eq!(dec_report.dst_used, 5);
/// assert_eq!(encoding_buf[1 + dec_report.parsed_size()], 0);
/// assert_eq!(dec_report.frame_size(), 5);
/// assert_eq!(current_idx, 16);
/// ```
pub fn encode_packet_with_cobs(

View File

@@ -162,7 +162,7 @@ pub trait SenderMapProvider<
/// * `ListenerMap`: [ListenerMapProvider] which maps listener keys to channel IDs.
/// * `EventSender`: [EventSendProvider] contained within the sender map which sends the events.
/// * `Event`: The event type. This type must implement the [GenericEvent]. Currently only [EventU32]
/// and [EventU16] are supported.
/// and [EventU16] are supported.
/// * `ParamProvider`: Auxiliary data which is sent with the event to provide optional context
/// information
pub struct EventManager<

View File

@@ -312,11 +312,11 @@ impl EventU32 {
/// # Parameter
///
/// * `severity`: Each event has a [severity][Severity]. The raw value of the severity will
/// be stored inside the uppermost 2 bits of the raw event ID
/// be stored inside the uppermost 2 bits of the raw event ID
/// * `group_id`: Related events can be grouped using a group ID. The group ID will occupy the
/// next 14 bits after the severity. Therefore, the size is limited by dec 16383 hex 0x3FFF.
/// next 14 bits after the severity. Therefore, the size is limited by dec 16383 hex 0x3FFF.
/// * `unique_id`: Each event has a unique 16 bit ID occupying the last 16 bits of the
/// raw event ID
/// raw event ID
pub fn new_checked(
severity: Severity,
group_id: <Self as GenericEvent>::GroupId,
@@ -486,11 +486,11 @@ impl EventU16 {
/// # Parameter
///
/// * `severity`: Each event has a [severity][Severity]. The raw value of the severity will
/// be stored inside the uppermost 2 bits of the raw event ID
/// be stored inside the uppermost 2 bits of the raw event ID
/// * `group_id`: Related events can be grouped using a group ID. The group ID will occupy the
/// next 6 bits after the severity. Therefore, the size is limited by dec 63 hex 0x3F.
/// next 6 bits after the severity. Therefore, the size is limited by dec 63 hex 0x3F.
/// * `unique_id`: Each event has a unique 8 bit ID occupying the last 8 bits of the
/// raw event ID
/// raw event ID
pub fn new_checked(
severity: Severity,
group_id: <Self as GenericEvent>::GroupId,

View File

@@ -39,9 +39,9 @@ pub trait ExecutableWithType: Executable {
///
/// * `executable`: Executable task
/// * `task_freq`: Optional frequency of task. Required for periodic and fixed cycle tasks.
/// If [None] is passed, no sleeping will be performed.
/// If [None] is passed, no sleeping will be performed.
/// * `op_code`: Operation code which is passed to the executable task
/// [operation call][Executable::periodic_op]
/// [operation call][Executable::periodic_op]
/// * `termination`: Optional termination handler which can cancel threads with a broadcast
pub fn exec_sched_single<
T: ExecutableWithType<Error = E> + Send + 'static + ?Sized,

View File

@@ -150,9 +150,9 @@ impl<
///
/// * `cfg` - Configuration of the server.
/// * `tm_source` - Generic TM source used by the server to pull telemetry packets which are
/// then sent back to the client.
/// then sent back to the client.
/// * `tc_receiver` - Any received telecommands which were decoded successfully will be
/// forwarded to this TC receiver.
/// forwarded to this TC receiver.
pub fn new(
cfg: ServerConfig,
tm_source: TmSource,
@@ -377,13 +377,13 @@ mod tests {
current_idx += 1;
let mut dec_report = cobs::decode_in_place_report(&mut read_buf[current_idx..])
.expect("COBS decoding failed");
assert_eq!(dec_report.dst_used, 5);
assert_eq!(dec_report.frame_size(), 5);
// Skip first sentinel byte.
assert_eq!(
&read_buf[current_idx..current_idx + INVERTED_PACKET.len()],
&INVERTED_PACKET
);
current_idx += dec_report.src_used;
current_idx += dec_report.parsed_size();
// End sentinel.
assert_eq!(read_buf[current_idx], 0, "invalid sentinel end byte");
current_idx += 1;
@@ -393,13 +393,13 @@ mod tests {
current_idx += 1;
dec_report = cobs::decode_in_place_report(&mut read_buf[current_idx..])
.expect("COBS decoding failed");
assert_eq!(dec_report.dst_used, 5);
assert_eq!(dec_report.frame_size(), 5);
// Skip first sentinel byte.
assert_eq!(
&read_buf[current_idx..current_idx + SIMPLE_PACKET.len()],
&SIMPLE_PACKET
);
current_idx += dec_report.src_used;
current_idx += dec_report.parsed_size();
// End sentinel.
assert_eq!(read_buf[current_idx], 0);
break;

View File

@@ -25,22 +25,22 @@ pub use crate::hal::std::tcp_spacepackets_server::{SpacepacketsTmSender, TcpSpac
///
/// * `addr` - Address of the TCP server.
/// * `inner_loop_delay` - If a client connects for a longer period, but no TC is received or
/// no TM needs to be sent, the TCP server will delay for the specified amount of time
/// to reduce CPU load.
/// no TM needs to be sent, the TCP server will delay for the specified amount of time
/// to reduce CPU load.
/// * `tm_buffer_size` - Size of the TM buffer used to read TM from the [PacketSource] and
/// encoding of that data. This buffer should at large enough to hold the maximum expected
/// TM size read from the packet source.
/// encoding of that data. This buffer should at large enough to hold the maximum expected
/// TM size read from the packet source.
/// * `tc_buffer_size` - Size of the TC buffer used to read encoded telecommands sent from
/// the client. It is recommended to make this buffer larger to allow reading multiple
/// consecutive packets as well, for example by using common buffer sizes like 4096 or 8192
/// byte. The buffer should at the very least be large enough to hold the maximum expected
/// telecommand size.
/// the client. It is recommended to make this buffer larger to allow reading multiple
/// consecutive packets as well, for example by using common buffer sizes like 4096 or 8192
/// byte. The buffer should at the very least be large enough to hold the maximum expected
/// telecommand size.
/// * `reuse_addr` - Can be used to set the `SO_REUSEADDR` option on the raw socket. This is
/// especially useful if the address and port are static for the server. Set to false by
/// default.
/// especially useful if the address and port are static for the server. Set to false by
/// default.
/// * `reuse_port` - Can be used to set the `SO_REUSEPORT` option on the raw socket. This is
/// especially useful if the address and port are static for the server. Set to false by
/// default.
/// especially useful if the address and port are static for the server. Set to false by
/// default.
#[derive(Debug, Copy, Clone)]
pub struct ServerConfig {
pub id: ComponentId,
@@ -211,12 +211,12 @@ impl<
///
/// * `cfg` - Configuration of the server.
/// * `tc_parser` - Parser which extracts telecommands from the raw bytestream received from
/// the client.
/// the client.
/// * `tm_sender` - Sends back telemetry to the client using the specified TM source.
/// * `tm_source` - Generic TM source used by the server to pull telemetry packets which are
/// then sent back to the client.
/// then sent back to the client.
/// * `tc_sender` - Any received telecommand which was decoded successfully will be forwarded
/// using this TC sender.
/// using this TC sender.
/// * `stop_signal` - Can be used to stop the server even if a connection is ongoing.
pub fn new(
cfg: ServerConfig,

View File

@@ -120,15 +120,15 @@ impl<
///
/// * `cfg` - Configuration of the server.
/// * `tm_source` - Generic TM source used by the server to pull telemetry packets which are
/// then sent back to the client.
/// then sent back to the client.
/// * `tc_sender` - Any received telecommands which were decoded successfully will be
/// forwarded using this [PacketSenderRaw].
/// forwarded using this [PacketSenderRaw].
/// * `validator` - Used to determine the space packets relevant for further processing and
/// to detect broken space packets.
/// to detect broken space packets.
/// * `handled_connection_hook` - Called to notify the user about a succesfully handled
/// connection.
/// connection.
/// * `stop_signal` - Can be used to shut down the TCP server even for longer running
/// connections.
/// connections.
pub fn new(
cfg: ServerConfig,
tm_source: TmSource,

View File

@@ -770,11 +770,11 @@ mod alloc_mod {
/// # Parameters
///
/// * `cfg` - Vector of tuples which represent a subpool. The first entry in the tuple specifies
/// the number of memory blocks in the subpool, the second entry the size of the blocks
/// the number of memory blocks in the subpool, the second entry the size of the blocks
/// * `spill_to_higher_subpools` - Specifies whether data will be spilled to higher subpools
/// if the next fitting subpool is full. This is useful to ensure the pool remains useful
/// for all data sizes as long as possible. However, an undesirable side-effect might be
/// the chocking of larger subpools by underdimensioned smaller subpools.
/// if the next fitting subpool is full. This is useful to ensure the pool remains useful
/// for all data sizes as long as possible. However, an undesirable side-effect might be
/// the chocking of larger subpools by underdimensioned smaller subpools.
#[derive(Debug, Clone)]
pub struct StaticPoolConfig {
cfg: Vec<SubpoolConfig>,

View File

@@ -409,7 +409,7 @@ mod tests {
assert!(res.event_was_enabled);
assert!(res.params_were_propagated);
let event_tm = event_rx.try_recv().expect("no event received");
let (tm, _) = PusTmReader::new(&event_tm.packet, 7).expect("reading TM failed");
let tm = PusTmReader::new(&event_tm.packet, 7).expect("reading TM failed");
assert_eq!(tm.service(), 5);
assert_eq!(tm.subservice(), Subservice::TmInfoReport as u8);
assert_eq!(tm.user_data().len(), 4 + param_data.len());
@@ -437,7 +437,7 @@ mod tests {
assert!(res.event_was_enabled);
assert!(res.params_were_propagated);
let event_tm = event_rx.try_recv().expect("no event received");
let (tm, _) = PusTmReader::new(&event_tm.packet, 7).expect("reading TM failed");
let tm = PusTmReader::new(&event_tm.packet, 7).expect("reading TM failed");
assert_eq!(tm.service(), 5);
assert_eq!(tm.subservice(), Subservice::TmInfoReport as u8);
assert_eq!(tm.user_data().len(), 4 + param_data.len());

View File

@@ -199,8 +199,12 @@ mod tests {
}
impl PusTestHarness for Pus5HandlerWithStoreTester {
fn init_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let init_token = self.handler.service_helper.verif_reporter_mut().add_tc(tc);
fn start_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let init_token = self
.handler
.service_helper
.verif_reporter_mut()
.start_verification(tc);
self.handler
.service_helper
.verif_reporter()
@@ -245,7 +249,7 @@ mod tests {
.write_to_be_bytes(&mut app_data)
.expect("writing test event failed");
let ping_tc = PusTcCreator::new(sp_header, sec_header, &app_data, true);
let token = test_harness.init_verification(&ping_tc);
let token = test_harness.start_verification(&ping_tc);
test_harness.send_tc(&token, &ping_tc);
let request_id = token.request_id();
test_harness.handle_one_tc().unwrap();
@@ -306,7 +310,7 @@ mod tests {
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, 0, 0);
let sec_header = PusTcSecondaryHeader::new_simple(5, 200);
let ping_tc = PusTcCreator::new_no_app_data(sp_header, sec_header, true);
let token = test_harness.init_verification(&ping_tc);
let token = test_harness.start_verification(&ping_tc);
test_harness.send_tc(&token, &ping_tc);
let result = test_harness.handle_one_tc();
assert!(result.is_ok());
@@ -326,7 +330,7 @@ mod tests {
let sec_header =
PusTcSecondaryHeader::new_simple(5, Subservice::TcEnableEventGeneration as u8);
let ping_tc = PusTcCreator::new(sp_header, sec_header, &[0, 1, 2], true);
let token = test_harness.init_verification(&ping_tc);
let token = test_harness.start_verification(&ping_tc);
test_harness.send_tc(&token, &ping_tc);
let result = test_harness.handle_one_tc();
assert!(result.is_err());

View File

@@ -959,15 +959,11 @@ pub mod std_mod {
possible_packet: &TcInMemory,
) -> Result<PusTcReader<'_>, PusTcFromMemError> {
self.cache(possible_packet)?;
Ok(PusTcReader::new(self.tc_slice_raw())
.map_err(EcssTmtcError::Pus)?
.0)
Ok(PusTcReader::new(self.tc_slice_raw()).map_err(EcssTmtcError::Pus)?)
}
fn convert(&self) -> Result<PusTcReader<'_>, PusTcFromMemError> {
Ok(PusTcReader::new(self.tc_slice_raw())
.map_err(EcssTmtcError::Pus)?
.0)
Ok(PusTcReader::new(self.tc_slice_raw()).map_err(EcssTmtcError::Pus)?)
}
}
@@ -1279,7 +1275,7 @@ pub mod test_util {
UniqueApidTargetId::new(TEST_APID, TEST_UNIQUE_ID_1);
pub trait PusTestHarness {
fn init_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>;
fn start_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>;
fn send_tc(&self, token: &VerificationToken<TcStateAccepted>, tc: &PusTcCreator);
fn read_next_tm(&mut self) -> PusTmReader<'_>;
fn check_no_tm_available(&self) -> bool;
@@ -1459,7 +1455,7 @@ pub mod tests {
let tm_pool = self.tm_pool.0.read().unwrap();
let tm_raw = tm_pool.read_as_vec(&tm_in_pool.store_addr).unwrap();
self.tm_buf[0..tm_raw.len()].copy_from_slice(&tm_raw);
PusTmReader::new(&self.tm_buf, 7).unwrap().0
PusTmReader::new(&self.tm_buf, 7).unwrap()
}
pub fn check_no_tm_available(&self) -> bool {
@@ -1476,7 +1472,7 @@ pub mod tests {
let tm_in_pool = next_msg.unwrap();
let tm_pool = self.tm_pool.0.read().unwrap();
let tm_raw = tm_pool.read_as_vec(&tm_in_pool.store_addr).unwrap();
let tm = PusTmReader::new(&tm_raw, 7).unwrap().0;
let tm = PusTmReader::new(&tm_raw, 7).unwrap();
assert_eq!(PusPacket::service(&tm), 1);
assert_eq!(PusPacket::subservice(&tm), subservice);
assert_eq!(tm.apid(), TEST_APID);
@@ -1584,9 +1580,7 @@ pub mod tests {
let next_msg = self.tm_receiver.try_recv();
assert!(next_msg.is_ok());
self.current_tm = Some(next_msg.unwrap().packet);
PusTmReader::new(self.current_tm.as_ref().unwrap(), 7)
.unwrap()
.0
PusTmReader::new(self.current_tm.as_ref().unwrap(), 7).unwrap()
}
pub fn check_no_tm_available(&self) -> bool {
@@ -1601,7 +1595,7 @@ pub mod tests {
let next_msg = self.tm_receiver.try_recv();
assert!(next_msg.is_ok());
let next_msg = next_msg.unwrap();
let tm = PusTmReader::new(next_msg.packet.as_slice(), 7).unwrap().0;
let tm = PusTmReader::new(next_msg.packet.as_slice(), 7).unwrap();
assert_eq!(PusPacket::service(&tm), 1);
assert_eq!(PusPacket::subservice(&tm), subservice);
assert_eq!(tm.apid(), TEST_APID);

View File

@@ -292,10 +292,10 @@ pub trait PusSchedulerProvider {
pool: &mut (impl PoolProvider + ?Sized),
) -> Result<TcInfo, ScheduleError> {
let check_tc = PusTcReader::new(tc)?;
if PusPacket::service(&check_tc.0) == 11 && PusPacket::subservice(&check_tc.0) == 4 {
if PusPacket::service(&check_tc) == 11 && PusPacket::subservice(&check_tc) == 4 {
return Err(ScheduleError::NestedScheduledTc);
}
let req_id = RequestId::from_tc(&check_tc.0);
let req_id = RequestId::from_tc(&check_tc);
match pool.add(tc) {
Ok(addr) => {
@@ -411,10 +411,10 @@ pub mod alloc_mod {
///
/// * `init_current_time` - The time to initialize the scheduler with.
/// * `time_margin` - This time margin is used when inserting new telecommands into the
/// schedule. If the release time of a new telecommand is earlier than the time margin
/// added to the current time, it will not be inserted into the schedule.
/// schedule. If the release time of a new telecommand is earlier than the time margin
/// added to the current time, it will not be inserted into the schedule.
/// * `tc_buf_size` - Buffer for temporary storage of telecommand packets. This buffer
/// should be large enough to accomodate the largest expected TC packets.
/// should be large enough to accomodate the largest expected TC packets.
pub fn new(init_current_time: UnixTime, time_margin: Duration) -> Self {
PusScheduler {
tc_map: Default::default(),
@@ -480,10 +480,10 @@ pub mod alloc_mod {
pool: &mut (impl PoolProvider + ?Sized),
) -> Result<TcInfo, ScheduleError> {
let check_tc = PusTcReader::new(tc)?;
if PusPacket::service(&check_tc.0) == 11 && PusPacket::subservice(&check_tc.0) == 4 {
if PusPacket::service(&check_tc) == 11 && PusPacket::subservice(&check_tc) == 4 {
return Err(ScheduleError::NestedScheduledTc);
}
let req_id = RequestId::from_tc(&check_tc.0);
let req_id = RequestId::from_tc(&check_tc);
match pool.add(tc) {
Ok(addr) => {
@@ -683,10 +683,10 @@ pub mod alloc_mod {
/// # Arguments
///
/// * `releaser` - Closure where the first argument is whether the scheduler is enabled and
/// the second argument is the telecommand information also containing the store
/// address. This closure should return whether the command should be deleted. Please
/// note that returning false might lead to memory leaks if the TC is not cleared from
/// the store in some other way.
/// the second argument is the telecommand information also containing the store
/// address. This closure should return whether the command should be deleted. Please
/// note that returning false might lead to memory leaks if the TC is not cleared from
/// the store in some other way.
/// * `tc_store` - The holding store of the telecommands.
/// * `tc_buf` - Buffer to hold each telecommand being released.
pub fn release_telecommands_with_buffer<R: FnMut(bool, &TcInfo, &[u8]) -> bool>(
@@ -1313,7 +1313,7 @@ mod tests {
let mut read_buf: [u8; 64] = [0; 64];
pool.read(&tc_info_0.addr(), &mut read_buf).unwrap();
let check_tc = PusTcReader::new(&read_buf).expect("incorrect Pus tc raw data");
assert_eq!(check_tc.0, base_ping_tc_simple_ctor(0, &[]));
assert_eq!(check_tc, base_ping_tc_simple_ctor(0, &[]));
assert_eq!(scheduler.num_scheduled_telecommands(), 1);
@@ -1335,8 +1335,8 @@ mod tests {
let read_len = pool.read(&addr_vec[0], &mut read_buf).unwrap();
let check_tc = PusTcReader::new(&read_buf).expect("incorrect Pus tc raw data");
assert_eq!(read_len, check_tc.1);
assert_eq!(check_tc.0, base_ping_tc_simple_ctor(0, &[]));
assert_eq!(read_len, check_tc.total_len());
assert_eq!(check_tc, base_ping_tc_simple_ctor(0, &[]));
}
#[test]
@@ -1362,8 +1362,8 @@ mod tests {
let read_len = pool.read(&info.addr, &mut buf).unwrap();
let check_tc = PusTcReader::new(&buf).expect("incorrect Pus tc raw data");
assert_eq!(read_len, check_tc.1);
assert_eq!(check_tc.0, base_ping_tc_simple_ctor(0, &[]));
assert_eq!(read_len, check_tc.total_len());
assert_eq!(check_tc, base_ping_tc_simple_ctor(0, &[]));
assert_eq!(scheduler.num_scheduled_telecommands(), 1);
@@ -1387,8 +1387,8 @@ mod tests {
let read_len = pool.read(&addr_vec[0], &mut buf).unwrap();
let check_tc = PusTcReader::new(&buf).expect("incorrect PUS tc raw data");
assert_eq!(read_len, check_tc.1);
assert_eq!(check_tc.0, base_ping_tc_simple_ctor(0, &[]));
assert_eq!(read_len, check_tc.total_len());
assert_eq!(check_tc, base_ping_tc_simple_ctor(0, &[]));
}
#[test]
@@ -2031,7 +2031,7 @@ mod tests {
assert_eq!(n, 1);
let time_reader = cds::CdsTime::from_bytes_with_u16_days(&buf[2..2 + 7]).unwrap();
assert_eq!(time_reader, time_writer);
let pus_tc_reader = PusTcReader::new(&buf[9..]).unwrap().0;
let pus_tc_reader = PusTcReader::new(&buf[9..]).unwrap();
assert_eq!(pus_tc_reader, ping_tc);
}

View File

@@ -309,8 +309,12 @@ mod tests {
}
impl PusTestHarness for Pus11HandlerWithStoreTester {
fn init_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let init_token = self.handler.service_helper.verif_reporter_mut().add_tc(tc);
fn start_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let init_token = self
.handler
.service_helper
.verif_reporter_mut()
.start_verification(tc);
self.handler
.service_helper
.verif_reporter()
@@ -383,7 +387,7 @@ mod tests {
let reply_header = SpHeader::new_for_unseg_tm(TEST_APID, 0, 0);
let tc_header = PusTcSecondaryHeader::new_simple(11, subservice as u8);
let enable_scheduling = PusTcCreator::new(reply_header, tc_header, &[0; 7], true);
let token = test_harness.init_verification(&enable_scheduling);
let token = test_harness.start_verification(&enable_scheduling);
test_harness.send_tc(&token, &enable_scheduling);
let request_id = token.request_id();
@@ -445,7 +449,7 @@ mod tests {
&sched_app_data[..written_len],
true,
);
let token = test_harness.init_verification(&enable_scheduling);
let token = test_harness.start_verification(&enable_scheduling);
test_harness.send_tc(&token, &enable_scheduling);
let request_id = token.request_id();

View File

@@ -180,8 +180,12 @@ mod tests {
}
impl PusTestHarness for Pus17HandlerWithStoreTester {
fn init_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let init_token = self.handler.service_helper.verif_reporter_mut().add_tc(tc);
fn start_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let init_token = self
.handler
.service_helper
.verif_reporter_mut()
.start_verification(tc);
self.handler
.service_helper
.verif_reporter()
@@ -238,8 +242,12 @@ mod tests {
}
impl PusTestHarness for Pus17HandlerWithVecTester {
fn init_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let init_token = self.handler.service_helper.verif_reporter_mut().add_tc(tc);
fn start_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
let init_token = self
.handler
.service_helper
.verif_reporter_mut()
.start_verification(tc);
self.handler
.service_helper
.verif_reporter()
@@ -279,7 +287,7 @@ mod tests {
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, 0, 0);
let sec_header = PusTcSecondaryHeader::new_simple(17, 1);
let ping_tc = PusTcCreator::new_no_app_data(sp_header, sec_header, true);
let token = test_harness.init_verification(&ping_tc);
let token = test_harness.start_verification(&ping_tc);
test_harness.send_tc(&token, &ping_tc);
let request_id = token.request_id();
let result = test_harness.handle_one_tc();
@@ -334,7 +342,7 @@ mod tests {
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, 0, 0);
let sec_header = PusTcSecondaryHeader::new_simple(3, 1);
let ping_tc = PusTcCreator::new_no_app_data(sp_header, sec_header, true);
let token = test_harness.init_verification(&ping_tc);
let token = test_harness.start_verification(&ping_tc);
test_harness.send_tc(&token, &ping_tc);
let result = test_harness.handle_one_tc();
assert!(result.is_err());
@@ -355,7 +363,7 @@ mod tests {
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, 0, 0);
let sec_header = PusTcSecondaryHeader::new_simple(17, 200);
let ping_tc = PusTcCreator::new_no_app_data(sp_header, sec_header, true);
let token = test_harness.init_verification(&ping_tc);
let token = test_harness.start_verification(&ping_tc);
test_harness.send_tc(&token, &ping_tc);
let result = test_harness.handle_one_tc();
assert!(result.is_ok());

View File

@@ -47,7 +47,7 @@
//! tc_header,
//! true
//! );
//! let init_token = reporter.add_tc(&pus_tc_0);
//! let init_token = reporter.start_verification(&pus_tc_0);
//!
//! // Complete success sequence for a telecommand
//! let accepted_token = reporter.acceptance_success(&sender, init_token, &EMPTY_STAMP).unwrap();
@@ -65,8 +65,7 @@
//! let store_guard = rg.read_with_guard(tm_in_store.store_addr);
//! tm_len = store_guard.read(&mut tm_buf).expect("Error reading TM slice");
//! }
//! let (pus_tm, _) = PusTmReader::new(&tm_buf[0..tm_len], 7)
//! .expect("Error reading verification TM");
//! let pus_tm = PusTmReader::new(&tm_buf[0..tm_len], 7).expect("Error reading verification TM");
//! if packet_idx == 0 {
//! assert_eq!(pus_tm.subservice(), 1);
//! } else if packet_idx == 1 {
@@ -228,7 +227,7 @@ pub struct VerificationToken<STATE> {
}
impl<STATE> VerificationToken<STATE> {
fn new(req_id: RequestId) -> VerificationToken<TcStateNone> {
pub fn new(req_id: RequestId) -> VerificationToken<TcStateNone> {
VerificationToken {
state: PhantomData,
request_id: req_id,
@@ -408,14 +407,10 @@ pub trait VerificationReportingProvider {
fn set_apid(&mut self, apid: Apid);
fn apid(&self) -> Apid;
fn add_tc(
&mut self,
fn start_verification(
&self,
pus_tc: &(impl CcsdsPacket + IsPusTelecommand),
) -> VerificationToken<TcStateNone> {
self.add_tc_with_req_id(RequestId::new(pus_tc))
}
fn add_tc_with_req_id(&mut self, req_id: RequestId) -> VerificationToken<TcStateNone>;
) -> VerificationToken<TcStateNone>;
fn acceptance_success(
&self,
@@ -482,7 +477,7 @@ pub trait VerificationReportingProvider {
/// the buffer passed to the API exposes by this struct will be used to serialize the source data.
/// This buffer may not be re-used to serialize the whole telemetry because that would overwrite
/// the source data itself.
#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct VerificationReportCreator {
pub dest_id: u16,
apid: u16,
@@ -518,17 +513,8 @@ impl VerificationReportCreator {
/// Initialize verification handling by passing a TC reference. This returns a token required
/// to call the acceptance functions
pub fn add_tc(
&mut self,
pus_tc: &(impl CcsdsPacket + IsPusTelecommand),
) -> VerificationToken<TcStateNone> {
self.add_tc_with_req_id(RequestId::new(pus_tc))
}
/// Same as [Self::add_tc] but pass a request ID instead of the direct telecommand.
/// This can be useful if the executing thread does not have full access to the telecommand.
pub fn add_tc_with_req_id(&mut self, req_id: RequestId) -> VerificationToken<TcStateNone> {
VerificationToken::<TcStateNone>::new(req_id)
pub fn read_request_id_from_tc(pus_tc: &(impl CcsdsPacket + IsPusTelecommand)) -> RequestId {
RequestId::new(pus_tc)
}
fn success_verification_no_step<'time, 'src_data>(
@@ -962,12 +948,26 @@ pub mod alloc_mod {
}
}
pub fn start_verification(
&self,
pus_tc: &(impl CcsdsPacket + IsPusTelecommand),
) -> VerificationToken<TcStateNone> {
VerificationToken::<TcStateNone>::new(
VerificationReportCreator::read_request_id_from_tc(pus_tc),
)
}
pub fn start_verification_with_req_id(
&self,
request_id: RequestId,
) -> VerificationToken<TcStateNone> {
VerificationToken::<TcStateNone>::new(request_id)
}
delegate!(
to self.reporter_creator {
pub fn set_apid(&mut self, apid: u16) -> bool;
pub fn apid(&self) -> u16;
pub fn add_tc(&mut self, pus_tc: &(impl CcsdsPacket + IsPusTelecommand)) -> VerificationToken<TcStateNone>;
pub fn add_tc_with_req_id(&mut self, req_id: RequestId) -> VerificationToken<TcStateNone>;
pub fn dest_id(&self) -> u16;
pub fn set_dest_id(&mut self, dest_id: u16);
}
@@ -985,11 +985,16 @@ pub mod alloc_mod {
to self.reporter_creator {
fn set_apid(&mut self, apid: Apid);
fn apid(&self) -> Apid;
fn add_tc(&mut self, pus_tc: &(impl CcsdsPacket + IsPusTelecommand)) -> VerificationToken<TcStateNone>;
fn add_tc_with_req_id(&mut self, req_id: RequestId) -> VerificationToken<TcStateNone>;
}
);
fn start_verification(
&self,
pus_tc: &(impl CcsdsPacket + IsPusTelecommand),
) -> VerificationToken<TcStateNone> {
VerificationToken::<TcStateNone>::new(RequestId::new(pus_tc))
}
fn owner_id(&self) -> ComponentId {
self.owner_id
}
@@ -1351,22 +1356,23 @@ pub mod test_util {
}
impl VerificationReportingProvider for TestVerificationReporter {
fn start_verification(
&self,
pus_tc: &(impl CcsdsPacket + IsPusTelecommand),
) -> VerificationToken<TcStateNone> {
let request_id = RequestId::new(pus_tc);
self.report_queue
.borrow_mut()
.push_back((request_id, VerificationReportInfo::Added));
VerificationToken::<TcStateNone>::new(RequestId::new(pus_tc))
}
fn set_apid(&mut self, _apid: Apid) {}
fn apid(&self) -> Apid {
0
}
fn add_tc_with_req_id(&mut self, req_id: RequestId) -> VerificationToken<TcStateNone> {
self.report_queue
.borrow_mut()
.push_back((req_id, VerificationReportInfo::Added));
VerificationToken {
state: PhantomData,
request_id: req_id,
}
}
fn acceptance_success(
&self,
_sender: &(impl EcssTmSender + ?Sized),
@@ -1823,15 +1829,16 @@ pub mod tests {
}
}
pub fn start_verification(&self) -> VerificationToken<TcStateNone> {
let tc_reader = PusTcReader::new(&self.tc).unwrap();
self.reporter.start_verification(&tc_reader)
}
#[allow(dead_code)]
fn set_dest_id(&mut self, dest_id: u16) {
self.reporter.set_dest_id(dest_id);
}
fn init(&mut self) -> VerificationToken<TcStateNone> {
self.reporter.add_tc(&PusTcReader::new(&self.tc).unwrap().0)
}
fn acceptance_success(
&self,
token: VerificationToken<TcStateNone>,
@@ -1909,7 +1916,7 @@ pub mod tests {
additional_data: None,
};
let mut service_queue = self.sender.service_queue.borrow_mut();
assert!(service_queue.len() >= 1);
assert!(!service_queue.is_empty());
let info = service_queue.pop_front().unwrap();
assert_eq!(info, cmp_info);
}
@@ -2081,8 +2088,8 @@ pub mod tests {
#[test]
fn test_basic_acceptance_success() {
let mut testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 16);
let token = testbench.init();
let testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 16);
let token = testbench.start_verification();
testbench
.acceptance_success(token, &EMPTY_STAMP)
.expect("sending acceptance success failed");
@@ -2092,7 +2099,7 @@ pub mod tests {
#[test]
fn test_basic_acceptance_failure() {
let mut testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 16);
let init_token = testbench.init();
let init_token = testbench.start_verification();
let timestamp = [1, 2, 3, 4, 5, 6, 7];
let fail_code = EcssEnumU16::new(2);
let fail_params = FailParams::new_no_fail_data(timestamp.as_slice(), &fail_code);
@@ -2105,7 +2112,7 @@ pub mod tests {
#[test]
fn test_basic_acceptance_failure_with_helper() {
let mut testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 16);
let init_token = testbench.init();
let init_token = testbench.start_verification();
let timestamp = [1, 2, 3, 4, 5, 6, 7];
let fail_code = EcssEnumU16::new(2);
let fail_params = FailParams::new_no_fail_data(timestamp.as_slice(), &fail_code);
@@ -2117,8 +2124,8 @@ pub mod tests {
#[test]
fn test_acceptance_fail_data_too_large() {
let mut testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 8);
let init_token = testbench.init();
let testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 8);
let init_token = testbench.start_verification();
let stamp_buf = [1, 2, 3, 4, 5, 6, 7];
let fail_code = EcssEnumU16::new(2);
let fail_data: [u8; 16] = [0; 16];
@@ -2149,13 +2156,13 @@ pub mod tests {
#[test]
fn test_basic_acceptance_failure_with_fail_data() {
let mut testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 16);
let testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 16);
let fail_code = EcssEnumU8::new(10);
let fail_data = EcssEnumU32::new(12);
let mut fail_data_raw = [0; 4];
fail_data.write_to_be_bytes(&mut fail_data_raw).unwrap();
let fail_params = FailParams::new(&EMPTY_STAMP, &fail_code, fail_data_raw.as_slice());
let init_token = testbench.init();
let init_token = testbench.start_verification();
testbench
.acceptance_failure(init_token, fail_params)
.expect("sending acceptance failure failed");
@@ -2173,7 +2180,7 @@ pub mod tests {
#[test]
fn test_start_failure() {
let mut testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 16);
let init_token = testbench.init();
let init_token = testbench.start_verification();
let fail_code = EcssEnumU8::new(22);
let fail_data: i32 = -12;
let mut fail_data_raw = [0; 4];
@@ -2192,7 +2199,7 @@ pub mod tests {
#[test]
fn test_start_failure_with_helper() {
let mut testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 16);
let token = testbench.init();
let token = testbench.start_verification();
let fail_code = EcssEnumU8::new(22);
let fail_data: i32 = -12;
let mut fail_data_raw = [0; 4];
@@ -2211,7 +2218,7 @@ pub mod tests {
#[test]
fn test_steps_success() {
let mut testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 16);
let token = testbench.init();
let token = testbench.start_verification();
let accepted_token = testbench
.acceptance_success(token, &EMPTY_STAMP)
.expect("acceptance failed");
@@ -2234,7 +2241,7 @@ pub mod tests {
#[test]
fn test_step_failure() {
let mut testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 16);
let token = testbench.init();
let token = testbench.start_verification();
let fail_code = EcssEnumU32::new(0x1020);
let fail_data: f32 = -22.3232;
let mut fail_data_raw = [0; 4];
@@ -2268,7 +2275,7 @@ pub mod tests {
#[test]
fn test_completion_failure() {
let mut testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 16);
let token = testbench.init();
let token = testbench.start_verification();
let fail_code = EcssEnumU32::new(0x1020);
let fail_params = FailParams::new_no_fail_data(&EMPTY_STAMP, &fail_code);
@@ -2291,7 +2298,7 @@ pub mod tests {
fn test_complete_success_sequence() {
let mut testbench =
VerificationReporterTestbench::new(TEST_COMPONENT_ID_0.id(), create_generic_ping(), 16);
let token = testbench.init();
let token = testbench.start_verification();
let accepted_token = testbench
.acceptance_success(token, &EMPTY_STAMP)
.expect("Sending acceptance success failed");
@@ -2313,7 +2320,7 @@ pub mod tests {
create_generic_ping(),
SequenceCounterHook::default(),
);
let token = testbench.init();
let token = testbench.start_verification();
let accepted_token = testbench
.acceptance_success(token, &EMPTY_STAMP)
.expect("Sending acceptance success failed");
@@ -2331,7 +2338,7 @@ pub mod tests {
#[test]
fn test_completion_failure_helper_string_param() {
let mut testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 32);
let token = testbench.init();
let token = testbench.start_verification();
let accepted_token = testbench
.acceptance_success(token, &EMPTY_STAMP)
.expect("Sending acceptance success failed");
@@ -2358,7 +2365,7 @@ pub mod tests {
#[test]
fn test_step_failure_helper_string_param() {
let mut testbench = VerificationReporterTestbench::new(0, create_generic_ping(), 32);
let token = testbench.init();
let token = testbench.start_verification();
let accepted_token = testbench
.acceptance_success(token, &EMPTY_STAMP)
.expect("Sending acceptance success failed");

View File

@@ -39,7 +39,7 @@ impl UniqueApidTargetId {
}
}
pub fn raw(&self) -> ComponentId {
pub const fn raw(&self) -> ComponentId {
((self.apid as u64) << 32) | (self.unique_id as u64)
}

View File

@@ -136,7 +136,7 @@ impl SequenceExecutionHelper {
/// with [Self::load]
/// * `sender` - The sender to send mode requests to the components
/// * `children_mode_store` - The mode store vector to keep track of the mode states of
/// children components
/// children components
pub fn run(
&mut self,
table: &SequenceModeTables,
@@ -597,7 +597,7 @@ impl SubsystemCommandingHelper {
}
fn update_internal_req_id(&mut self) {
let new_internal_req_id = self.request_id().unwrap() << 8
let new_internal_req_id = (self.request_id().unwrap() << 8)
| self.seq_exec_helper.current_sequence_index().unwrap() as u32;
self.seq_exec_helper.set_request_id(new_internal_req_id);
self.active_internal_request_id = Some(new_internal_req_id);

View File

@@ -107,9 +107,9 @@ fn test_threaded_usage() {
Ok(event_tm) => {
let tm = PusTmReader::new(event_tm.packet.as_slice(), 7)
.expect("Deserializing TM failed");
assert_eq!(tm.0.service(), 5);
assert_eq!(tm.0.subservice(), 1);
let src_data = tm.0.source_data();
assert_eq!(tm.service(), 5);
assert_eq!(tm.subservice(), 1);
let src_data = tm.source_data();
assert!(!src_data.is_empty());
assert_eq!(src_data.len(), 4);
let event =
@@ -137,9 +137,9 @@ fn test_threaded_usage() {
Ok(event_tm) => {
let tm = PusTmReader::new(event_tm.packet.as_slice(), 7)
.expect("Deserializing TM failed");
assert_eq!(tm.0.service(), 5);
assert_eq!(tm.0.subservice(), 2);
let src_data = tm.0.source_data();
assert_eq!(tm.service(), 5);
assert_eq!(tm.subservice(), 2);
let src_data = tm.source_data();
assert!(!src_data.is_empty());
assert_eq!(src_data.len(), 12);
let event =

View File

@@ -89,9 +89,9 @@ pub mod crossbeam_test {
let pg = tc_guard.read_with_guard(tc_addr);
tc_len = pg.read(&mut tc_buf).unwrap();
}
let (_tc, _) = PusTcReader::new(&tc_buf[0..tc_len]).unwrap();
let _tc = PusTcReader::new(&tc_buf[0..tc_len]).unwrap();
let token = reporter_with_sender_0.add_tc_with_req_id(req_id_0);
let token = reporter_with_sender_0.start_verification_with_req_id(req_id_0);
let accepted_token = reporter_with_sender_0
.acceptance_success(&sender, token, &FIXED_STAMP)
.expect("Acceptance success failed");
@@ -125,8 +125,8 @@ pub mod crossbeam_test {
let pg = tc_guard.read_with_guard(tc_addr);
tc_len = pg.read(&mut tc_buf).unwrap();
}
let (tc, _) = PusTcReader::new(&tc_buf[0..tc_len]).unwrap();
let token = reporter_with_sender_1.add_tc(&tc);
let tc = PusTcReader::new(&tc_buf[0..tc_len]).unwrap();
let token = reporter_with_sender_1.start_verification(&tc);
let accepted_token = reporter_with_sender_1
.acceptance_success(&sender_1, token, &FIXED_STAMP)
.expect("Acceptance success failed");
@@ -156,7 +156,7 @@ pub mod crossbeam_test {
.read(&mut tm_buf)
.expect("Error reading TM slice");
}
let (pus_tm, _) =
let pus_tm =
PusTmReader::new(&tm_buf[0..tm_len], 7).expect("Error reading verification TM");
let req_id =
RequestId::from_bytes(&pus_tm.source_data()[0..RequestId::SIZE_AS_BYTES])