From cba4a29396962475b20334b6953a7328baeba018 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 3 Apr 2024 18:04:32 +0200 Subject: [PATCH] that gets the job done --- satrs-example/Cargo.toml | 2 + satrs-example/satrs-tmtc/common.py | 11 +- satrs-example/satrs-tmtc/pus_tc.py | 61 +++++++-- satrs-example/src/ccsds.rs | 27 ++-- satrs-example/src/config.rs | 46 ++++--- satrs-example/src/events.rs | 25 +++- satrs-example/src/main.rs | 4 +- satrs-example/src/tcp.rs | 19 +-- satrs/src/encoding/ccsds.rs | 43 ++++--- satrs/src/hal/std/tcp_spacepackets_server.rs | 34 ++--- satrs/src/pus/event.rs | 128 ++++++++++++------- satrs/src/tmtc/ccsds_distrib.rs | 64 ++++++---- 12 files changed, 290 insertions(+), 174 deletions(-) diff --git a/satrs-example/Cargo.toml b/satrs-example/Cargo.toml index 1893db8..b22904b 100644 --- a/satrs-example/Cargo.toml +++ b/satrs-example/Cargo.toml @@ -17,6 +17,8 @@ zerocopy = "0.6" csv = "1" num_enum = "0.7" thiserror = "1" +lazy_static = "1" +strum = { version = "0.26", features = ["derive"] } derive-new = "0.5" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/satrs-example/satrs-tmtc/common.py b/satrs-example/satrs-tmtc/common.py index 8f57e54..26ecb16 100644 --- a/satrs-example/satrs-tmtc/common.py +++ b/satrs-example/satrs-tmtc/common.py @@ -36,8 +36,15 @@ class EventU32: ) -class RequestTargetId(enum.IntEnum): - ACS = 1 +class Apid(enum.IntEnum): + SCHED = 1 + GENERIC_PUS = 2 + ACS = 3 + CFDP = 4 + + +class AcsId(enum.IntEnum): + MGM_0 = 0 class AcsHkIds(enum.IntEnum): diff --git a/satrs-example/satrs-tmtc/pus_tc.py b/satrs-example/satrs-tmtc/pus_tc.py index 0a1b03a..88a8831 100644 --- a/satrs-example/satrs-tmtc/pus_tc.py +++ b/satrs-example/satrs-tmtc/pus_tc.py @@ -1,23 +1,35 @@ import datetime +import struct import logging from spacepackets.ccsds import CdsShortTimestamp from spacepackets.ecss import PusTelecommand from tmtccmd.config import CmdTreeNode +from tmtccmd.pus.tc.s200_fsfw_mode import Mode from tmtccmd.tmtc import DefaultPusQueueHelper from tmtccmd.pus.s11_tc_sched import create_time_tagged_cmd -from tmtccmd.pus.tc.s3_fsfw_hk import create_request_one_hk_command +from tmtccmd.pus.s200_fsfw_mode import Subservice as ModeSubservice -from common import ( - EXAMPLE_PUS_APID, - make_addressable_id, - RequestTargetId, - AcsHkIds, -) +from common import EXAMPLE_PUS_APID, AcsId, Apid _LOGGER = logging.getLogger(__name__) +def create_set_mode_cmd( + apid: int, unique_id: int, mode: int, submode: int +) -> PusTelecommand: + app_data = bytearray() + app_data.extend(struct.pack("!I", unique_id)) + app_data.extend(struct.pack("!I", mode)) + app_data.extend(struct.pack("!H", submode)) + return PusTelecommand( + service=200, + subservice=ModeSubservice.TC_MODE_COMMAND, + apid=apid, + app_data=app_data, + ) + + def create_cmd_definition_tree() -> CmdTreeNode: root_node = CmdTreeNode.root_node() @@ -95,12 +107,33 @@ def pack_pus_telecommands(q: DefaultPusQueueHelper, cmd_path: str): ) if cmd_path_list[0] == "acs": assert len(cmd_path_list) >= 2 - if cmd_path_list[1] == "mgm": + if cmd_path_list[1] == "mgms": assert len(cmd_path_list) >= 3 - if cmd_path_list[2] == "one_shot_hk": - q.add_log_cmd("Sending HK one shot request") - q.add_pus_tc( - create_request_one_hk_command( - make_addressable_id(RequestTargetId.ACS, AcsHkIds.MGM_SET) + if cmd_path_list[2] == "hk": + if cmd_path_list[3] == "one_shot_hk": + q.add_log_cmd("Sending HK one shot request") + # TODO: Fix + # q.add_pus_tc( + # create_request_one_hk_command( + # make_addressable_id(Apid.ACS, AcsId.MGM_SET) + # ) + # ) + if cmd_path_list[2] == "mode": + if cmd_path_list[3] == "set_mode": + handle_set_mode_cmd( + q, "MGM 0", cmd_path_list[4], Apid.ACS, AcsId.MGM_0 ) - ) + + +def handle_set_mode_cmd( + q: DefaultPusQueueHelper, target_str: str, mode_str: str, apid: int, unique_id: int +): + if mode_str == "off": + q.add_log_cmd(f"Sending Mode OFF to {target_str}") + q.add_pus_tc(create_set_mode_cmd(apid, unique_id, Mode.OFF, 0)) + elif mode_str == "on": + q.add_log_cmd(f"Sending Mode ON to {target_str}") + q.add_pus_tc(create_set_mode_cmd(apid, unique_id, Mode.ON, 0)) + elif mode_str == "normal": + q.add_log_cmd(f"Sending Mode NORMAL to {target_str}") + q.add_pus_tc(create_set_mode_cmd(apid, unique_id, Mode.NORMAL, 0)) diff --git a/satrs-example/src/ccsds.rs b/satrs-example/src/ccsds.rs index 7f15fb0..53d8a14 100644 --- a/satrs-example/src/ccsds.rs +++ b/satrs-example/src/ccsds.rs @@ -1,7 +1,9 @@ +use satrs::encoding::ccsds::PacketIdValidator; use satrs::pus::ReceivesEcssPusTc; -use satrs::spacepackets::{CcsdsPacket, SpHeader}; +use satrs::spacepackets::{CcsdsPacket, PacketId, SpHeader}; use satrs::tmtc::{CcsdsPacketHandler, ReceivesCcsdsTc}; use satrs_example::config::components::Apid; +use satrs_example::config::PACKET_ID_VALIDATOR; #[derive(Clone)] pub struct CcsdsReceiver< @@ -11,6 +13,16 @@ pub struct CcsdsReceiver< pub tc_source: TcSource, } +impl< + TcSource: ReceivesCcsdsTc + ReceivesEcssPusTc + Clone + 'static, + E: 'static, + > PacketIdValidator for CcsdsReceiver +{ + fn validate(&self, packet_id: u16) -> bool { + PACKET_ID_VALIDATOR.contains(&PacketId::from(packet_id)) + } +} + impl< TcSource: ReceivesCcsdsTc + ReceivesEcssPusTc + Clone + 'static, E: 'static, @@ -18,16 +30,7 @@ impl< { type Error = E; - fn valid_apids(&self) -> &'static [u16] { - &[ - Apid::GenericPus as u16, - Apid::Acs as u16, - Apid::Sched as u16, - Apid::EventTm as u16, - ] - } - - fn handle_known_apid( + fn handle_packet_with_valid_apid( &mut self, sp_header: &SpHeader, tc_raw: &[u8], @@ -39,7 +42,7 @@ impl< Ok(()) } - fn handle_unknown_apid( + fn handle_packet_with_unknown_apid( &mut self, sp_header: &SpHeader, _tc_raw: &[u8], diff --git a/satrs-example/src/config.rs b/satrs-example/src/config.rs index 07d01ed..f016c88 100644 --- a/satrs-example/src/config.rs +++ b/satrs-example/src/config.rs @@ -1,7 +1,12 @@ -use satrs::res_code::ResultU16; +use lazy_static::lazy_static; +use satrs::{ + res_code::ResultU16, + spacepackets::{PacketId, PacketType}, +}; use satrs_mib::res_code::ResultU16Info; use satrs_mib::resultcode; -use std::net::Ipv4Addr; +use std::{collections::HashSet, net::Ipv4Addr}; +use strum::IntoEnumIterator; use num_enum::{IntoPrimitive, TryFromPrimitive}; use satrs::{ @@ -36,6 +41,16 @@ pub const SERVER_PORT: u16 = 7301; pub const TEST_EVENT: EventU32TypedSev = EventU32TypedSev::::const_new(0, 0); +lazy_static! { + pub static ref PACKET_ID_VALIDATOR: HashSet = { + let mut set = HashSet::new(); + for id in components::Apid::iter() { + set.insert(PacketId::const_new(PacketType::Tc, true, id as u16)); + } + set + }; +} + pub mod tmtc_err { use super::*; @@ -102,26 +117,25 @@ pub mod mode_err { pub mod components { use satrs::request::UniqueApidTargetId; + use strum::EnumIter; - #[derive(Copy, Clone, PartialEq, Eq)] + #[derive(Copy, Clone, PartialEq, Eq, EnumIter)] pub enum Apid { - VerificationTm = 1, - Sched = 2, - EventTm = 3, - HkTm = 4, - GenericPus = 5, - Acs = 6, - Cfdp = 7, + Sched = 1, + GenericPus = 2, + Acs = 3, + Cfdp = 4, } // Component IDs for components with the PUS APID. #[derive(Copy, Clone, PartialEq, Eq)] pub enum PusId { - PusRouting = 0, - PusTest = 1, - PusAction = 2, - PusMode = 3, - PusHk = 4, + PusEventManagement = 0, + PusRouting = 1, + PusTest = 2, + PusAction = 3, + PusMode = 4, + PusHk = 5, } #[derive(Copy, Clone, PartialEq, Eq)] @@ -132,7 +146,7 @@ pub mod components { 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::EventTm as u16, 0); + 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 = diff --git a/satrs-example/src/events.rs b/satrs-example/src/events.rs index a9e98c1..4d7ea9f 100644 --- a/satrs-example/src/events.rs +++ b/satrs-example/src/events.rs @@ -3,8 +3,10 @@ use std::sync::mpsc::{self}; use crate::pus::create_verification_reporter; use satrs::event_man::{EventMessageU32, EventRoutingError}; use satrs::params::WritableToBeBytes; +use satrs::pus::event::EventTmHookProvider; use satrs::pus::verification::VerificationReporter; use satrs::pus::EcssTmSenderCore; +use satrs::request::UniqueApidTargetId; use satrs::{ event_man::{ EventManagerWithBoundedMpsc, EventSendProvider, EventU32SenderMpscBounded, @@ -18,11 +20,22 @@ use satrs::{ }, spacepackets::time::cds::CdsTime, }; -use satrs_example::config::components; use satrs_example::config::components::PUS_EVENT_MANAGEMENT; use crate::update_time; +// This helper sets the APID of the event sender for the PUS telemetry. +#[derive(Default)] +pub struct EventApidSetter { + pub next_apid: u16, +} + +impl EventTmHookProvider for EventApidSetter { + fn modify_tm(&self, tm: &mut satrs::spacepackets::ecss::tm::PusTmCreator) { + tm.set_apid(self.next_apid); + } +} + /// The PUS event handler subscribes for all events and converts them into ECSS PUS 5 event /// packets. It also handles the verification completion of PUS event service requests. pub struct PusEventHandler { @@ -33,6 +46,7 @@ pub struct PusEventHandler { time_provider: CdsTime, timestamp: [u8; 7], verif_handler: VerificationReporter, + event_apid_setter: EventApidSetter, } impl PusEventHandler { @@ -47,12 +61,7 @@ impl PusEventHandler { // All events sent to the manager are routed to the PUS event manager, which generates PUS event // telemetry for each event. - let event_reporter = EventReporter::new( - PUS_EVENT_MANAGEMENT.raw(), - components::Apid::EventTm as u16, - 128, - ) - .unwrap(); + let event_reporter = EventReporter::new(PUS_EVENT_MANAGEMENT.raw(), 0, 0, 128).unwrap(); let pus_event_dispatcher = DefaultPusEventU32Dispatcher::new_with_default_backend(event_reporter); let pus_event_man_send_provider = EventU32SenderMpscBounded::new( @@ -72,6 +81,7 @@ impl PusEventHandler { timestamp: [0; 7], verif_handler, tm_sender, + event_apid_setter: EventApidSetter::default(), } } @@ -113,6 +123,7 @@ impl PusEventHandler { let param_vec = event_msg.params().map_or(Vec::new(), |param| { param.to_vec().expect("failed to convert params to vec") }); + self.event_apid_setter.next_apid = UniqueApidTargetId::from(event_msg.sender_id()).apid; self.pus_event_dispatcher .generate_pus_event_tm_generic( &self.tm_sender, diff --git a/satrs-example/src/main.rs b/satrs-example/src/main.rs index ae315e5..a6456d6 100644 --- a/satrs-example/src/main.rs +++ b/satrs-example/src/main.rs @@ -23,7 +23,7 @@ use satrs_example::config::pool::{create_sched_tc_pool, create_static_pools}; use satrs_example::config::tasks::{ FREQ_MS_AOCS, FREQ_MS_EVENT_HANDLING, FREQ_MS_PUS_STACK, FREQ_MS_UDP_TMTC, }; -use satrs_example::config::{OBSW_SERVER_ADDR, SERVER_PORT}; +use satrs_example::config::{OBSW_SERVER_ADDR, PACKET_ID_VALIDATOR, SERVER_PORT}; use tmtc::PusTcSourceProviderDynamic; use udp::DynamicUdpTmHandler; @@ -191,6 +191,7 @@ fn static_tmtc_pool_main() { tcp_server_cfg, sync_tm_tcp_source.clone(), tcp_ccsds_distributor, + PACKET_ID_VALIDATOR.clone(), ) .expect("tcp server creation failed"); @@ -415,6 +416,7 @@ fn dyn_tmtc_pool_main() { tcp_server_cfg, sync_tm_tcp_source.clone(), tcp_ccsds_distributor, + PACKET_ID_VALIDATOR.clone(), ) .expect("tcp server creation failed"); diff --git a/satrs-example/src/tcp.rs b/satrs-example/src/tcp.rs index 561a030..04bb136 100644 --- a/satrs-example/src/tcp.rs +++ b/satrs-example/src/tcp.rs @@ -1,5 +1,5 @@ use std::{ - collections::VecDeque, + collections::{HashSet, VecDeque}, sync::{Arc, Mutex}, }; @@ -10,17 +10,9 @@ use satrs::{ spacepackets::PacketId, tmtc::{CcsdsDistributor, CcsdsError, ReceivesCcsdsTc, TmPacketSourceCore}, }; -use satrs_example::config::components; use crate::ccsds::CcsdsReceiver; -pub const PACKET_ID_LOOKUP: &[PacketId] = &[ - PacketId::const_tc(true, components::Apid::GenericPus as u16), - PacketId::const_tc(true, components::Apid::EventTm as u16), - PacketId::const_tc(true, components::Apid::Acs as u16), - PacketId::const_tc(true, components::Apid::Sched as u16), -]; - #[derive(Default, Clone)] pub struct SyncTcpTmSource { tm_queue: Arc>>>, @@ -82,6 +74,7 @@ pub type TcpServerType = TcpSpacepacketsServer< CcsdsError, SyncTcpTmSource, CcsdsDistributor, MpscErrorType>, + HashSet, >; pub struct TcpTask< @@ -108,14 +101,10 @@ impl< cfg: ServerConfig, tm_source: SyncTcpTmSource, tc_receiver: CcsdsDistributor, MpscErrorType>, + packet_id_lookup: HashSet, ) -> Result { Ok(Self { - server: TcpSpacepacketsServer::new( - cfg, - tm_source, - tc_receiver, - Box::new(PACKET_ID_LOOKUP), - )?, + server: TcpSpacepacketsServer::new(cfg, tm_source, tc_receiver, packet_id_lookup)?, }) } diff --git a/satrs/src/encoding/ccsds.rs b/satrs/src/encoding/ccsds.rs index 37694d7..2107787 100644 --- a/satrs/src/encoding/ccsds.rs +++ b/satrs/src/encoding/ccsds.rs @@ -2,60 +2,71 @@ use alloc::vec::Vec; #[cfg(feature = "alloc")] use hashbrown::HashSet; +#[cfg(feature = "std")] +use std::collections::HashSet as StdHashSet; + use spacepackets::PacketId; use crate::tmtc::ReceivesTcCore; -pub trait PacketIdLookup { +pub trait PacketIdValidator { fn validate(&self, packet_id: u16) -> bool; } #[cfg(feature = "alloc")] -impl PacketIdLookup for Vec { +impl PacketIdValidator for Vec { fn validate(&self, packet_id: u16) -> bool { self.contains(&packet_id) } } #[cfg(feature = "alloc")] -impl PacketIdLookup for HashSet { +impl PacketIdValidator for HashSet { fn validate(&self, packet_id: u16) -> bool { self.contains(&packet_id) } } -impl PacketIdLookup for [u16] { +impl PacketIdValidator for [u16] { fn validate(&self, packet_id: u16) -> bool { self.binary_search(&packet_id).is_ok() } } -impl PacketIdLookup for &[u16] { +impl PacketIdValidator for &[u16] { fn validate(&self, packet_id: u16) -> bool { self.binary_search(&packet_id).is_ok() } } #[cfg(feature = "alloc")] -impl PacketIdLookup for Vec { - fn validate(&self, packet_id: u16) -> bool { - self.contains(&PacketId::from(packet_id)) - } -} -#[cfg(feature = "alloc")] -impl PacketIdLookup for HashSet { +impl PacketIdValidator for Vec { fn validate(&self, packet_id: u16) -> bool { self.contains(&PacketId::from(packet_id)) } } -impl PacketIdLookup for [PacketId] { +#[cfg(feature = "alloc")] +impl PacketIdValidator for HashSet { + fn validate(&self, packet_id: u16) -> bool { + self.contains(&PacketId::from(packet_id)) + } +} + +#[cfg(feature = "std")] +impl PacketIdValidator for StdHashSet { + fn validate(&self, packet_id: u16) -> bool { + self.contains(&PacketId::from(packet_id)) + } +} + +impl PacketIdValidator for [PacketId] { fn validate(&self, packet_id: u16) -> bool { self.binary_search(&PacketId::from(packet_id)).is_ok() } } -impl PacketIdLookup for &[PacketId] { +impl PacketIdValidator for &[PacketId] { fn validate(&self, packet_id: u16) -> bool { self.binary_search(&PacketId::from(packet_id)).is_ok() } @@ -75,7 +86,7 @@ impl PacketIdLookup for &[PacketId] { /// error will be returned. pub fn parse_buffer_for_ccsds_space_packets( buf: &mut [u8], - packet_id_lookup: &(impl PacketIdLookup + ?Sized), + packet_id_validator: &(impl PacketIdValidator + ?Sized), tc_receiver: &mut (impl ReceivesTcCore + ?Sized), next_write_idx: &mut usize, ) -> Result { @@ -88,7 +99,7 @@ pub fn parse_buffer_for_ccsds_space_packets( break; } let packet_id = u16::from_be_bytes(buf[current_idx..current_idx + 2].try_into().unwrap()); - if packet_id_lookup.validate(packet_id) { + if packet_id_validator.validate(packet_id) { let length_field = u16::from_be_bytes(buf[current_idx + 4..current_idx + 6].try_into().unwrap()); let packet_size = length_field + 7; diff --git a/satrs/src/hal/std/tcp_spacepackets_server.rs b/satrs/src/hal/std/tcp_spacepackets_server.rs index 257f0c1..72b9e28 100644 --- a/satrs/src/hal/std/tcp_spacepackets_server.rs +++ b/satrs/src/hal/std/tcp_spacepackets_server.rs @@ -4,10 +4,8 @@ use std::{ net::{SocketAddr, TcpListener, TcpStream}, }; -use alloc::boxed::Box; - use crate::{ - encoding::{ccsds::PacketIdLookup, parse_buffer_for_ccsds_space_packets}, + encoding::{ccsds::PacketIdValidator, parse_buffer_for_ccsds_space_packets}, tmtc::{ReceivesTc, TmPacketSource}, }; @@ -16,17 +14,19 @@ use super::tcp_server::{ }; /// Concrete [TcpTcParser] implementation for the [TcpSpacepacketsServer]. -pub struct SpacepacketsTcParser { - packet_id_lookup: Box, +pub struct SpacepacketsTcParser { + packet_id_lookup: PacketIdChecker, } -impl SpacepacketsTcParser { - pub fn new(packet_id_lookup: Box) -> Self { +impl SpacepacketsTcParser { + pub fn new(packet_id_lookup: PacketIdChecker) -> Self { Self { packet_id_lookup } } } -impl TcpTcParser for SpacepacketsTcParser { +impl TcpTcParser + for SpacepacketsTcParser +{ fn handle_tc_parsing( &mut self, tc_buffer: &mut [u8], @@ -38,7 +38,7 @@ impl TcpTcParser for SpacepacketsTc // Reader vec full, need to parse for packets. conn_result.num_received_tcs += parse_buffer_for_ccsds_space_packets( &mut tc_buffer[..current_write_idx], - self.packet_id_lookup.as_ref(), + &self.packet_id_lookup, tc_receiver.upcast_mut(), next_write_idx, ) @@ -95,6 +95,7 @@ pub struct TcpSpacepacketsServer< TcError: 'static, TmSource: TmPacketSource, TcReceiver: ReceivesTc, + PacketIdChecker: PacketIdValidator, > { generic_server: TcpTmtcGenericServer< TmError, @@ -102,7 +103,7 @@ pub struct TcpSpacepacketsServer< TmSource, TcReceiver, SpacepacketsTmSender, - SpacepacketsTcParser, + SpacepacketsTcParser, >, } @@ -111,7 +112,8 @@ impl< TcError: 'static, TmSource: TmPacketSource, TcReceiver: ReceivesTc, - > TcpSpacepacketsServer + PacketIdChecker: PacketIdValidator, + > TcpSpacepacketsServer { /// /// ## Parameter @@ -127,12 +129,12 @@ impl< cfg: ServerConfig, tm_source: TmSource, tc_receiver: TcReceiver, - packet_id_lookup: Box, + packet_id_checker: PacketIdChecker, ) -> Result { Ok(Self { generic_server: TcpTmtcGenericServer::new( cfg, - SpacepacketsTcParser::new(packet_id_lookup), + SpacepacketsTcParser::new(packet_id_checker), SpacepacketsTmSender::default(), tm_source, tc_receiver, @@ -170,7 +172,7 @@ mod tests { thread, }; - use alloc::{boxed::Box, sync::Arc}; + use alloc::sync::Arc; use hashbrown::HashSet; use spacepackets::{ ecss::{tc::PusTcCreator, WritablePusPacket}, @@ -194,12 +196,12 @@ mod tests { tc_receiver: SyncTcCacher, tm_source: SyncTmSource, packet_id_lookup: HashSet, - ) -> TcpSpacepacketsServer<(), (), SyncTmSource, SyncTcCacher> { + ) -> TcpSpacepacketsServer<(), (), SyncTmSource, SyncTcCacher, HashSet> { TcpSpacepacketsServer::new( ServerConfig::new(*addr, Duration::from_millis(2), 1024, 1024), tm_source, tc_receiver, - Box::new(packet_id_lookup), + packet_id_lookup, ) .expect("TCP server generation failed") } diff --git a/satrs/src/pus/event.rs b/satrs/src/pus/event.rs index a1f4d81..0462101 100644 --- a/satrs/src/pus/event.rs +++ b/satrs/src/pus/event.rs @@ -6,8 +6,10 @@ use spacepackets::ByteConversionError; use spacepackets::{SpHeader, MAX_APID}; use crate::pus::EcssTmSenderCore; + #[cfg(feature = "alloc")] -pub use alloc_mod::EventReporter; +pub use alloc_mod::*; + pub use spacepackets::ecss::event::*; pub struct EventReportCreator { @@ -16,102 +18,98 @@ pub struct EventReportCreator { } impl EventReportCreator { - pub fn new(apid: u16) -> Option { + pub fn new(apid: u16, dest_id: u16) -> Option { if apid > MAX_APID { return None; } - Some(Self { - // msg_count: 0, - dest_id: 0, - apid, - }) + Some(Self { dest_id, apid }) } pub fn event_info<'time, 'src_data>( &self, - src_data_buf: &'src_data mut [u8], time_stamp: &'time [u8], event_id: impl EcssEnumeration, - aux_data: Option<&'src_data [u8]>, + params: Option<&'src_data [u8]>, + src_data_buf: &'src_data mut [u8], ) -> Result, ByteConversionError> { self.generate_and_send_generic_tm( - src_data_buf, Subservice::TmInfoReport, time_stamp, event_id, - aux_data, + params, + src_data_buf, ) } pub fn event_low_severity<'time, 'src_data>( &self, - src_data_buf: &'src_data mut [u8], time_stamp: &'time [u8], event_id: impl EcssEnumeration, - aux_data: Option<&'src_data [u8]>, + params: Option<&'src_data [u8]>, + src_data_buf: &'src_data mut [u8], ) -> Result, ByteConversionError> { self.generate_and_send_generic_tm( - src_data_buf, Subservice::TmLowSeverityReport, time_stamp, event_id, - aux_data, + params, + src_data_buf, ) } pub fn event_medium_severity<'time, 'src_data>( &self, - buf: &'src_data mut [u8], time_stamp: &'time [u8], event_id: impl EcssEnumeration, - aux_data: Option<&'src_data [u8]>, + params: Option<&'src_data [u8]>, + buf: &'src_data mut [u8], ) -> Result, ByteConversionError> { self.generate_and_send_generic_tm( - buf, Subservice::TmMediumSeverityReport, time_stamp, event_id, - aux_data, + params, + buf, ) } pub fn event_high_severity<'time, 'src_data>( &self, - src_data_buf: &'src_data mut [u8], time_stamp: &'time [u8], event_id: impl EcssEnumeration, - aux_data: Option<&'src_data [u8]>, + params: Option<&'src_data [u8]>, + src_data_buf: &'src_data mut [u8], ) -> Result, ByteConversionError> { self.generate_and_send_generic_tm( - src_data_buf, Subservice::TmHighSeverityReport, time_stamp, event_id, - aux_data, + params, + src_data_buf, ) } fn generate_and_send_generic_tm<'time, 'src_data>( &self, - src_data_buf: &'src_data mut [u8], subservice: Subservice, time_stamp: &'time [u8], event_id: impl EcssEnumeration, - aux_data: Option<&'src_data [u8]>, + params: Option<&'src_data [u8]>, + src_data_buf: &'src_data mut [u8], ) -> Result, ByteConversionError> { - self.generate_generic_event_tm(src_data_buf, subservice, time_stamp, event_id, aux_data) + self.generate_generic_event_tm(subservice, time_stamp, event_id, params, src_data_buf) } fn generate_generic_event_tm<'time, 'src_data>( &self, - src_data_buf: &'src_data mut [u8], subservice: Subservice, time_stamp: &'time [u8], event_id: impl EcssEnumeration, - aux_data: Option<&'src_data [u8]>, + params: Option<&'src_data [u8]>, + src_data_buf: &'src_data mut [u8], ) -> Result, ByteConversionError> { let mut src_data_len = event_id.size(); - if let Some(aux_data) = aux_data { + if let Some(aux_data) = params { src_data_len += aux_data.len(); } source_buffer_large_enough(src_data_buf.len(), src_data_len)?; @@ -121,7 +119,7 @@ impl EventReportCreator { let mut current_idx = 0; event_id.write_to_be_bytes(&mut src_data_buf[0..event_id.size()])?; current_idx += event_id.size(); - if let Some(aux_data) = aux_data { + if let Some(aux_data) = params { src_data_buf[current_idx..current_idx + aux_data.len()].copy_from_slice(aux_data); current_idx += aux_data.len(); } @@ -142,25 +140,56 @@ mod alloc_mod { use alloc::vec::Vec; use core::cell::RefCell; - pub struct EventReporter { + pub trait EventTmHookProvider { + fn modify_tm(&self, tm: &mut PusTmCreator); + } + + #[derive(Default)] + pub struct DummyEventHook {} + + impl EventTmHookProvider for DummyEventHook { + fn modify_tm(&self, _tm: &mut PusTmCreator) {} + } + + pub struct EventReporter { id: ComponentId, // Use interior mutability pattern here. This is just an intermediate buffer to the PUS event packet // generation. source_data_buf: RefCell>, pub report_creator: EventReportCreator, + pub tm_hook: EventTmHook, } - impl EventReporter { + impl EventReporter { pub fn new( id: ComponentId, - apid: u16, + default_apid: u16, + default_dest_id: u16, max_event_id_and_aux_data_size: usize, ) -> Option { - let reporter = EventReportCreator::new(apid)?; + let reporter = EventReportCreator::new(default_apid, default_dest_id)?; Some(Self { id, source_data_buf: RefCell::new(vec![0; max_event_id_and_aux_data_size]), report_creator: reporter, + tm_hook: DummyEventHook::default(), + }) + } + } + impl EventReporter { + pub fn new_with_hook( + id: ComponentId, + default_apid: u16, + default_dest_id: u16, + max_event_id_and_aux_data_size: usize, + tm_hook: EventTmHook, + ) -> Option { + let reporter = EventReportCreator::new(default_apid, default_dest_id)?; + Some(Self { + id, + source_data_buf: RefCell::new(vec![0; max_event_id_and_aux_data_size]), + report_creator: reporter, + tm_hook, }) } @@ -169,13 +198,14 @@ mod alloc_mod { sender: &(impl EcssTmSenderCore + ?Sized), time_stamp: &[u8], event_id: impl EcssEnumeration, - aux_data: Option<&[u8]>, + params: Option<&[u8]>, ) -> Result<(), EcssTmtcError> { let mut mut_buf = self.source_data_buf.borrow_mut(); - let tm_creator = self + let mut tm_creator = self .report_creator - .event_info(mut_buf.as_mut_slice(), time_stamp, event_id, aux_data) + .event_info(time_stamp, event_id, params, mut_buf.as_mut_slice()) .map_err(PusError::ByteConversion)?; + self.tm_hook.modify_tm(&mut tm_creator); sender.send_tm(self.id, tm_creator.into())?; Ok(()) } @@ -185,13 +215,14 @@ mod alloc_mod { sender: &(impl EcssTmSenderCore + ?Sized), time_stamp: &[u8], event_id: impl EcssEnumeration, - aux_data: Option<&[u8]>, + params: Option<&[u8]>, ) -> Result<(), EcssTmtcError> { let mut mut_buf = self.source_data_buf.borrow_mut(); - let tm_creator = self + let mut tm_creator = self .report_creator - .event_low_severity(mut_buf.as_mut_slice(), time_stamp, event_id, aux_data) + .event_low_severity(time_stamp, event_id, params, mut_buf.as_mut_slice()) .map_err(PusError::ByteConversion)?; + self.tm_hook.modify_tm(&mut tm_creator); sender.send_tm(self.id, tm_creator.into())?; Ok(()) } @@ -201,13 +232,14 @@ mod alloc_mod { sender: &(impl EcssTmSenderCore + ?Sized), time_stamp: &[u8], event_id: impl EcssEnumeration, - aux_data: Option<&[u8]>, + params: Option<&[u8]>, ) -> Result<(), EcssTmtcError> { let mut mut_buf = self.source_data_buf.borrow_mut(); - let tm_creator = self + let mut tm_creator = self .report_creator - .event_medium_severity(mut_buf.as_mut_slice(), time_stamp, event_id, aux_data) + .event_medium_severity(time_stamp, event_id, params, mut_buf.as_mut_slice()) .map_err(PusError::ByteConversion)?; + self.tm_hook.modify_tm(&mut tm_creator); sender.send_tm(self.id, tm_creator.into())?; Ok(()) } @@ -217,13 +249,14 @@ mod alloc_mod { sender: &(impl EcssTmSenderCore + ?Sized), time_stamp: &[u8], event_id: impl EcssEnumeration, - aux_data: Option<&[u8]>, + params: Option<&[u8]>, ) -> Result<(), EcssTmtcError> { let mut mut_buf = self.source_data_buf.borrow_mut(); - let tm_creator = self + let mut tm_creator = self .report_creator - .event_high_severity(mut_buf.as_mut_slice(), time_stamp, event_id, aux_data) + .event_high_severity(time_stamp, event_id, params, mut_buf.as_mut_slice()) .map_err(PusError::ByteConversion)?; + self.tm_hook.modify_tm(&mut tm_creator); sender.send_tm(self.id, tm_creator.into())?; Ok(()) } @@ -346,6 +379,7 @@ mod tests { let reporter = EventReporter::new( TEST_COMPONENT_ID_0.id(), EXAMPLE_APID, + 0, max_event_aux_data_buf, ); assert!(reporter.is_some()); @@ -440,7 +474,7 @@ mod tests { fn insufficient_buffer() { let mut sender = TestSender::default(); for i in 0..3 { - let reporter = EventReporter::new(0, EXAMPLE_APID, i); + let reporter = EventReporter::new(0, EXAMPLE_APID, 0, i); assert!(reporter.is_some()); let mut reporter = reporter.unwrap(); check_buf_too_small(&mut reporter, &mut sender, i); diff --git a/satrs/src/tmtc/ccsds_distrib.rs b/satrs/src/tmtc/ccsds_distrib.rs index 7b1ac34..813ffdd 100644 --- a/satrs/src/tmtc/ccsds_distrib.rs +++ b/satrs/src/tmtc/ccsds_distrib.rs @@ -81,7 +81,10 @@ //! let mutable_handler_ref = ccsds_distributor.packet_handler_mut(); //! mutable_handler_ref.mutable_foo(); //! ``` -use crate::tmtc::{ReceivesCcsdsTc, ReceivesTcCore}; +use crate::{ + encoding::ccsds::PacketIdValidator, + tmtc::{ReceivesCcsdsTc, ReceivesTcCore}, +}; use core::fmt::{Display, Formatter}; use spacepackets::{ByteConversionError, CcsdsPacket, SpHeader}; #[cfg(feature = "std")] @@ -93,14 +96,16 @@ use std::error::Error; /// instance of this handler to the [CcsdsDistributor]. The distributor will use the trait /// interface to dispatch received packets to the user based on the Application Process Identifier /// (APID) field of the CCSDS packet. -pub trait CcsdsPacketHandler { +pub trait CcsdsPacketHandler: PacketIdValidator { type Error; - // TODO: Rework this to return a boolean based on u16 input.. - fn valid_apids(&self) -> &'static [u16]; - fn handle_known_apid(&mut self, sp_header: &SpHeader, tc_raw: &[u8]) - -> Result<(), Self::Error>; - fn handle_unknown_apid( + fn handle_packet_with_valid_apid( + &mut self, + sp_header: &SpHeader, + tc_raw: &[u8], + ) -> Result<(), Self::Error>; + + fn handle_packet_with_unknown_apid( &mut self, sp_header: &SpHeader, tc_raw: &[u8], @@ -184,18 +189,16 @@ impl, E: 'static> CcsdsDistributor< } fn dispatch_ccsds(&mut self, sp_header: &SpHeader, tc_raw: &[u8]) -> Result<(), CcsdsError> { - let apid = sp_header.apid(); - let valid_apids = self.packet_handler.valid_apids(); - for &valid_apid in valid_apids { - if valid_apid == apid { - return self - .packet_handler - .handle_known_apid(sp_header, tc_raw) - .map_err(|e| CcsdsError::CustomError(e)); - } + //let valid_apids = self.packet_handler.valid_apids(); + let valid_apid = self.packet_handler().validate(sp_header.packet_id().raw()); + if valid_apid { + return self + .packet_handler + .handle_packet_with_valid_apid(sp_header, tc_raw) + .map_err(|e| CcsdsError::CustomError(e)); } self.packet_handler - .handle_unknown_apid(sp_header, tc_raw) + .handle_packet_with_unknown_apid(sp_header, tc_raw) .map_err(|e| CcsdsError::CustomError(e)) } } @@ -242,13 +245,16 @@ pub(crate) mod tests { pub unknown_packet_queue: VecDeque<(u16, Vec)>, } + impl PacketIdValidator for BasicApidHandlerSharedQueue { + fn validate(&self, packet_id: u16) -> bool { + &[0x000, 0x002].contains(&packet_id) + } + } + impl CcsdsPacketHandler for BasicApidHandlerSharedQueue { type Error = (); - fn valid_apids(&self) -> &'static [u16] { - &[0x000, 0x002] - } - fn handle_known_apid( + fn handle_packet_with_valid_apid( &mut self, sp_header: &SpHeader, tc_raw: &[u8], @@ -262,7 +268,7 @@ pub(crate) mod tests { Ok(()) } - fn handle_unknown_apid( + fn handle_packet_with_unknown_apid( &mut self, sp_header: &SpHeader, tc_raw: &[u8], @@ -277,14 +283,16 @@ pub(crate) mod tests { } } + impl PacketIdValidator for BasicApidHandlerOwnedQueue { + fn validate(&self, packet_id: u16) -> bool { + &[0x000, 0x002].contains(&packet_id) + } + } + impl CcsdsPacketHandler for BasicApidHandlerOwnedQueue { type Error = (); - fn valid_apids(&self) -> &'static [u16] { - &[0x000, 0x002] - } - - fn handle_known_apid( + fn handle_packet_with_valid_apid( &mut self, sp_header: &SpHeader, tc_raw: &[u8], @@ -295,7 +303,7 @@ pub(crate) mod tests { Ok(()) } - fn handle_unknown_apid( + fn handle_packet_with_unknown_apid( &mut self, sp_header: &SpHeader, tc_raw: &[u8],