diff --git a/satrs-core/Cargo.toml b/satrs-core/Cargo.toml index 11aa619..da11060 100644 --- a/satrs-core/Cargo.toml +++ b/satrs-core/Cargo.toml @@ -32,6 +32,7 @@ default-features = false [dependencies.serde] version = "1.0" default-features = false +optional = true [dependencies.spacepackets] path = "../spacepackets" @@ -50,6 +51,7 @@ version = "1.0" default = ["std"] std = ["downcast-rs/std", "alloc", "bus", "postcard/use-std", "crossbeam-channel/std", "serde/std"] alloc = ["serde/alloc"] +serde = ["dep:serde"] heapless = [] doc-images = [] diff --git a/satrs-core/src/event_man.rs b/satrs-core/src/event_man.rs index 3219c0b..530df51 100644 --- a/satrs-core/src/event_man.rs +++ b/satrs-core/src/event_man.rs @@ -211,9 +211,9 @@ impl>) -> Self { - let listener_table = Box::new(DefaultListenerTableProvider::default()); - let sender_table = - Box::new(DefaultSenderTableProvider::::default()); + let listener_table: Box = Box::default(); + let sender_table: Box> = + Box::default(); Self::new_custom_tables(listener_table, sender_table, event_receiver) } } diff --git a/satrs-core/src/events.rs b/satrs-core/src/events.rs index 1c06945..ae0452c 100644 --- a/satrs-core/src/events.rs +++ b/satrs-core/src/events.rs @@ -136,17 +136,14 @@ impl EventBase { impl EventBase { #[inline] fn raw(&self) -> u32 { - (((self.severity as u32) << 30) | ((self.group_id as u32) << 16) | self.unique_id as u32) - as u32 + ((self.severity as u32) << 30) | ((self.group_id as u32) << 16) | self.unique_id as u32 } } impl EventBase { #[inline] fn raw(&self) -> u16 { - (((self.severity as u16) << 14) as u16 - | ((self.group_id as u16) << 8) as u16 - | self.unique_id as u16) as u16 + ((self.severity as u16) << 14) | ((self.group_id as u16) << 8) | self.unique_id as u16 } } diff --git a/satrs-core/src/pool.rs b/satrs-core/src/pool.rs index 70d9dcd..ebc404e 100644 --- a/satrs-core/src/pool.rs +++ b/satrs-core/src/pool.rs @@ -136,7 +136,7 @@ impl StoreAddr { pub const INVALID_ADDR: u32 = 0xFFFFFFFF; pub fn raw(&self) -> u32 { - ((self.pool_idx as u32) << 16) as u32 | self.packet_idx as u32 + ((self.pool_idx as u32) << 16) | self.packet_idx as u32 } } @@ -239,7 +239,7 @@ impl LocalPool { fn validate_addr(&self, addr: &StoreAddr) -> Result<(), StoreError> { let pool_idx = addr.pool_idx as usize; - if pool_idx as usize >= self.pool_cfg.cfg.len() { + if pool_idx >= self.pool_cfg.cfg.len() { return Err(StoreError::InvalidStoreId( StoreIdError::InvalidSubpool(addr.pool_idx), Some(*addr), diff --git a/satrs-core/src/pus/hk.rs b/satrs-core/src/pus/hk.rs new file mode 100644 index 0000000..3771670 --- /dev/null +++ b/satrs-core/src/pus/hk.rs @@ -0,0 +1,8 @@ +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Subservice { + TcEnableGeneration = 5, + TcDisableGeneration = 6, + TmHkPacket = 25, + TcGenerateOneShotHk = 27, + TcModifyCollectionInterval = 31, +} diff --git a/satrs-core/src/pus/mod.rs b/satrs-core/src/pus/mod.rs index ef06002..ba4629a 100644 --- a/satrs-core/src/pus/mod.rs +++ b/satrs-core/src/pus/mod.rs @@ -12,6 +12,7 @@ use spacepackets::{ByteConversionError, SizeMissmatch}; pub mod event; pub mod event_man; +pub mod hk; pub mod verification; /// Generic error type which is also able to wrap a user send error with the user supplied type E. diff --git a/satrs-core/src/pus/verification.rs b/satrs-core/src/pus/verification.rs index b2466c3..1da862b 100644 --- a/satrs-core/src/pus/verification.rs +++ b/satrs-core/src/pus/verification.rs @@ -569,7 +569,7 @@ impl VerificationReporterBasic { ) -> Result> { let mut source_data_len = size_of::(); if let Some(step) = step { - source_data_len += step.byte_width() as usize; + source_data_len += step.byte_width(); } source_buffer_large_enough(buf.len(), source_data_len)?; let mut idx = 0; @@ -577,7 +577,7 @@ impl VerificationReporterBasic { idx += RequestId::SIZE_AS_BYTES; if let Some(step) = step { // Size check was done beforehand - step.write_to_be_bytes(&mut buf[idx..idx + step.byte_width() as usize]) + step.write_to_be_bytes(&mut buf[idx..idx + step.byte_width()]) .unwrap(); } let mut sp_header = SpHeader::tm_unseg(self.apid(), 0, 0).unwrap(); @@ -601,10 +601,9 @@ impl VerificationReporterBasic { params: &'a FailParams, ) -> Result> { let mut idx = 0; - let mut source_data_len = - RequestId::SIZE_AS_BYTES + params.failure_code.byte_width() as usize; + let mut source_data_len = RequestId::SIZE_AS_BYTES + params.failure_code.byte_width(); if let Some(step) = step { - source_data_len += step.byte_width() as usize; + source_data_len += step.byte_width(); } if let Some(failure_data) = params.failure_data { source_data_len += failure_data.len(); @@ -614,14 +613,14 @@ impl VerificationReporterBasic { idx += RequestId::SIZE_AS_BYTES; if let Some(step) = step { // Size check done beforehand - step.write_to_be_bytes(&mut buf[idx..idx + step.byte_width() as usize]) + step.write_to_be_bytes(&mut buf[idx..idx + step.byte_width()]) .unwrap(); - idx += step.byte_width() as usize; + idx += step.byte_width(); } params .failure_code - .write_to_be_bytes(&mut buf[idx..idx + params.failure_code.byte_width() as usize])?; - idx += params.failure_code.byte_width() as usize; + .write_to_be_bytes(&mut buf[idx..idx + params.failure_code.byte_width()])?; + idx += params.failure_code.byte_width(); if let Some(failure_data) = params.failure_data { buf[idx..idx + failure_data.len()].copy_from_slice(failure_data); } @@ -709,8 +708,8 @@ mod allocmod { source_data_buf: vec![ 0; RequestId::SIZE_AS_BYTES - + cfg.step_field_width as usize - + cfg.fail_code_field_width as usize + + cfg.step_field_width + + cfg.fail_code_field_width + cfg.max_fail_data_len ], seq_counter: cfg.seq_counter.clone(), diff --git a/satrs-core/src/tmtc/mod.rs b/satrs-core/src/tmtc/mod.rs index b1d0b3d..0a31362 100644 --- a/satrs-core/src/tmtc/mod.rs +++ b/satrs-core/src/tmtc/mod.rs @@ -5,10 +5,11 @@ //! directly dispatch received packets to packet listeners based on packet fields like the CCSDS //! Application Process ID (APID) or the ECSS PUS service type. This allows for fast packet //! routing without the overhead and complication of using message queues. However, it also requires -use crate::error::{FsrcErrorRaw, FsrcGroupIds}; use downcast_rs::{impl_downcast, Downcast}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; use spacepackets::tc::PusTc; -use spacepackets::SpHeader; +use spacepackets::{ByteConversionError, SizeMissmatch, SpHeader}; #[cfg(feature = "alloc")] pub mod ccsds_distrib; @@ -19,24 +20,27 @@ pub mod tm_helper; pub use ccsds_distrib::{CcsdsDistributor, CcsdsError, CcsdsPacketHandler}; pub use pus_distrib::{PusDistributor, PusServiceProvider}; -const _RAW_PACKET_ERROR: &str = "raw-tmtc"; -const _CCSDS_ERROR: &str = "ccsds-tmtc"; -const _PUS_ERROR: &str = "pus-tmtc"; +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct AddressableId { + pub target_id: u32, + pub unique_id: u32, +} -// TODO: A macro for general and unknown errors would be nice -const _FROM_BYTES_SLICE_TOO_SMALL_ERROR: FsrcErrorRaw = FsrcErrorRaw::new( - FsrcGroupIds::Tmtc as u8, - 0, - _RAW_PACKET_ERROR, - "FROM_BYTES_SLICE_TOO_SMALL_ERROR", -); - -const _FROM_BYTES_ZEROCOPY_ERROR: FsrcErrorRaw = FsrcErrorRaw::new( - FsrcGroupIds::Tmtc as u8, - 1, - _RAW_PACKET_ERROR, - "FROM_BYTES_ZEROCOPY_ERROR", -); +impl AddressableId { + pub fn from_raw_be(buf: &[u8]) -> Result { + if buf.len() < 8 { + return Err(ByteConversionError::FromSliceTooSmall(SizeMissmatch { + found: buf.len(), + expected: 8, + })); + } + Ok(Self { + target_id: u32::from_be_bytes(buf[0..4].try_into().unwrap()), + unique_id: u32::from_be_bytes(buf[4..8].try_into().unwrap()), + }) + } +} /// Generic trait for object which can receive any telecommands in form of a raw bytestream, with /// no assumptions about the received protocol. diff --git a/satrs-example/pyclient/main.py b/satrs-example/pyclient/main.py index 03ef60e..be63b2b 100755 --- a/satrs-example/pyclient/main.py +++ b/satrs-example/pyclient/main.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 """Example client for the sat-rs example application""" +import enum +import struct import sys import time from typing import Optional @@ -8,9 +10,9 @@ import tmtccmd from spacepackets.ecss import PusTelemetry, PusTelecommand, PusVerificator from spacepackets.ecss.pus_17_test import Service17Tm from spacepackets.ecss.pus_1_verification import UnpackParams, Service1Tm -from spacepackets.util import UnsignedByteField from tmtccmd import CcsdsTmtcBackend, TcHandlerBase, ProcedureParamsWrapper +from tmtccmd.tc.pus_3_fsfw_hk import generate_one_hk_command, make_sid from tmtccmd.core.base import BackendRequest from tmtccmd.pus import VerificationWrapper from tmtccmd.tm import CcsdsTmHandler, SpecificApidHandlerBase @@ -85,6 +87,13 @@ class SatRsConfigHook(TmTcCfgHookBase): info="PUS Service 17 Test", op_code_entry=srv_17, ) + srv_3 = OpCodeEntry() + srv_3.add(HkOpCodes.GENERATE_ONE_SHOT, "Generate AOCS one shot HK") + defs.add_service( + name=CoreServiceList.SERVICE_3, + info="PUS Service 3 Housekeeping", + op_code_entry=srv_3 + ) return defs def perform_mode_operation(self, tmtc_backend: CcsdsTmtcBackend, mode: int): @@ -158,6 +167,24 @@ class PusHandler(SpecificApidHandlerBase): self.printer.handle_long_tm_print(packet_if=tm_packet, info_if=tm_packet) +def make_addressable_id(target_id: int, unique_id: int) -> bytes: + byte_string = bytearray(struct.pack("!I", target_id)) + byte_string.extend(struct.pack("!I", unique_id)) + return byte_string + + +class RequestTargetId(enum.IntEnum): + ACS = 1 + + +class AcsHkIds(enum.IntEnum): + MGM_SET = 1 + + +class HkOpCodes: + GENERATE_ONE_SHOT = ["0", "oneshot"] + + class TcHandler(TcHandlerBase): def __init__( self, @@ -197,17 +224,27 @@ class TcHandler(TcHandlerBase): ) def feed_cb(self, helper: ProcedureWrapper, wrapper: FeedWrapper): - self.queue_helper.queue_wrapper = wrapper.queue_wrapper + q = self.queue_helper + q.queue_wrapper = wrapper.queue_wrapper if helper.proc_type == TcProcedureType.DEFAULT: def_proc = helper.to_def_procedure() service = def_proc.service + op_code = def_proc.op_code if ( service == CoreServiceList.SERVICE_17 or service == CoreServiceList.SERVICE_17_ALT ): - return self.queue_helper.add_pus_tc( + q.add_log_cmd("Sending PUS ping telecommand") + return q.add_pus_tc( PusTelecommand(service=17, subservice=1) ) + if service == CoreServiceList.SERVICE_3: + if op_code in HkOpCodes.GENERATE_ONE_SHOT: + q.add_log_cmd("Sending HK one shot request") + q.add_pus_tc( + generate_one_hk_command(make_addressable_id(RequestTargetId.ACS, AcsHkIds.MGM_SET)) + ) + pass def main(): diff --git a/satrs-example/src/hk.rs b/satrs-example/src/hk.rs new file mode 100644 index 0000000..96cd37b --- /dev/null +++ b/satrs-example/src/hk.rs @@ -0,0 +1,15 @@ +#![allow(dead_code)] +pub type CollectionIntervalFactor = u32; + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum AcsHkIds { + TestMgmSet = 1, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum HkRequest { + OneShot(u32), + Enable(u32), + Disable(u32), + ModifyCollectionInterval(CollectionIntervalFactor), +} diff --git a/satrs-example/src/lib.rs b/satrs-example/src/lib.rs index e2b3be6..83a095b 100644 --- a/satrs-example/src/lib.rs +++ b/satrs-example/src/lib.rs @@ -3,24 +3,47 @@ use std::net::Ipv4Addr; use satrs_mib::res_code::{ResultU16, ResultU16Info}; use satrs_mib::resultcode; +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum RequestTargetId { + AcsSubsystem = 1, +} + #[derive(Debug)] pub enum GroupId { Tmtc = 0, + Hk = 1, } pub const OBSW_SERVER_ADDR: Ipv4Addr = Ipv4Addr::UNSPECIFIED; pub const SERVER_PORT: u16 = 7301; -#[resultcode] -pub const INVALID_PUS_SERVICE: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 0); -#[resultcode] -pub const INVALID_PUS_SUBSERVICE: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 1); +pub mod tmtc_err { + use super::*; -#[resultcode(info = "Not enough data inside the TC application data field")] -pub const NOT_ENOUGH_APP_DATA: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 2); + #[resultcode] + pub const INVALID_PUS_SERVICE: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 0); + #[resultcode] + pub const INVALID_PUS_SUBSERVICE: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 1); -pub const TMTC_RESULTS: &[ResultU16Info] = &[ - INVALID_PUS_SERVICE_EXT, - INVALID_PUS_SUBSERVICE_EXT, - NOT_ENOUGH_APP_DATA_EXT, -]; + #[resultcode(info = "Not enough data inside the TC application data field")] + pub const NOT_ENOUGH_APP_DATA: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 2); + + pub const TMTC_RESULTS: &[ResultU16Info] = &[ + INVALID_PUS_SERVICE_EXT, + INVALID_PUS_SUBSERVICE_EXT, + NOT_ENOUGH_APP_DATA_EXT, + ]; +} + +pub mod hk_err { + use super::*; + + #[resultcode] + pub const TARGET_ID_MISSING: ResultU16 = ResultU16::const_new(GroupId::Hk as u8, 0); + #[resultcode] + pub const UNIQUE_ID_MISSING: ResultU16 = ResultU16::const_new(GroupId::Hk as u8, 1); + #[resultcode] + pub const UNKNOWN_TARGET_ID: ResultU16 = ResultU16::const_new(GroupId::Hk as u8, 2); + #[resultcode] + pub const COLLECTION_INTERVAL_MISSING: ResultU16 = ResultU16::const_new(GroupId::Hk as u8, 3); +} diff --git a/satrs-example/src/main.rs b/satrs-example/src/main.rs index c955507..f929798 100644 --- a/satrs-example/src/main.rs +++ b/satrs-example/src/main.rs @@ -1,7 +1,10 @@ mod ccsds; +mod hk; mod pus; +mod requests; mod tmtc; +use crate::requests::RequestWithToken; use crate::tmtc::{core_tmtc_task, CoreTmtcArgs, TmStore, PUS_APID}; use satrs_core::event_man::{ EventManagerWithMpscQueue, MpscEventReceiver, MpscEventU32SendProvider, SendEventProvider, @@ -19,14 +22,16 @@ use satrs_core::pus::verification::{ use satrs_core::pus::{EcssTmError, EcssTmSender}; use satrs_core::seq_count::SimpleSeqCountProvider; use satrs_core::tmtc::CcsdsError; -use satrs_example::{OBSW_SERVER_ADDR, SERVER_PORT}; +use satrs_example::{RequestTargetId, OBSW_SERVER_ADDR, SERVER_PORT}; use spacepackets::time::cds::TimeProvider; use spacepackets::time::TimeWriter; use spacepackets::tm::PusTm; +use std::collections::HashMap; use std::net::{IpAddr, SocketAddr}; -use std::sync::mpsc::channel; +use std::sync::mpsc::{channel, TryRecvError}; use std::sync::{mpsc, Arc, RwLock}; use std::thread; +use std::time::Duration; struct TmFunnel { tm_funnel_rx: mpsc::Receiver, @@ -78,6 +83,7 @@ fn main() { let sender = MpscVerifSender::new(tm_store.clone(), tm_funnel_tx.clone()); let verif_cfg = VerificationReporterCfg::new( PUS_APID, + #[allow(clippy::box_default)] Box::new(SimpleSeqCountProvider::default()), 1, 2, @@ -97,15 +103,21 @@ fn main() { PusEventDispatcher::new(event_reporter, Box::new(pus_tm_backend)); let (pus_event_man_tx, pus_event_man_rx) = channel(); let pus_event_man_send_provider = MpscEventU32SendProvider::new(1, pus_event_man_tx); - let mut reporter1 = reporter_with_sender_0.clone(); + let mut reporter_event_handler = reporter_with_sender_0.clone(); + let mut reporter_aocs = reporter_with_sender_0.clone(); event_man.subscribe_all(pus_event_man_send_provider.id()); + let mut request_map = HashMap::new(); + let (acs_thread_tx, acs_thread_rx) = channel::(); + request_map.insert(RequestTargetId::AcsSubsystem as u32, acs_thread_tx); + // Create clones here to allow move for thread 0 let core_args = CoreTmtcArgs { tm_store: tm_store_helper.clone(), tm_sender: tm_funnel_tx.clone(), event_sender, event_request_tx, + request_map, }; println!("Starting TMTC task"); @@ -135,7 +147,7 @@ fn main() { let mut sender = EventTmSender::new(tm_store_helper, tm_funnel_tx); let mut time_provider = TimeProvider::new_with_u16_days(0, 0); let mut report_completion = |event_req: EventRequestWithToken, timestamp: &[u8]| { - reporter1 + reporter_event_handler .completion_success(event_req.token, timestamp) .expect("Sending completion success failed"); }; @@ -167,9 +179,37 @@ fn main() { } }); + println!("Starting AOCS thread"); + let jh3 = thread::spawn(move || { + let mut timestamp: [u8; 7] = [0; 7]; + let mut time_provider = TimeProvider::new_with_u16_days(0, 0); + loop { + match acs_thread_rx.try_recv() { + Ok(request) => { + println!("ACS thread: Received HK request {:?}", request.0); + update_time(&mut time_provider, &mut timestamp); + let started_token = reporter_aocs + .start_success(request.1, ×tamp) + .expect("Sending start success failed"); + reporter_aocs + .completion_success(started_token, ×tamp) + .expect("Sending completion success failed"); + } + Err(e) => match e { + TryRecvError::Empty => {} + TryRecvError::Disconnected => { + println!("ACS thread: Message Queue TX disconnected!") + } + }, + } + thread::sleep(Duration::from_millis(500)); + } + }); + jh0.join().expect("Joining UDP TMTC server thread failed"); jh1.join().expect("Joining TM Funnel thread failed"); jh2.join().expect("Joining Event Manager thread failed"); + jh3.join().expect("Joining AOCS thread failed"); } pub fn update_time(time_provider: &mut TimeProvider, timestamp: &mut [u8]) { diff --git a/satrs-example/src/pus.rs b/satrs-example/src/pus.rs index 20ba72a..49dc6bc 100644 --- a/satrs-example/src/pus.rs +++ b/satrs-example/src/pus.rs @@ -1,28 +1,33 @@ +use crate::hk::{CollectionIntervalFactor, HkRequest}; +use crate::requests::{Request, RequestWithToken}; use crate::tmtc::TmStore; use satrs_core::events::EventU32; use satrs_core::pool::StoreAddr; use satrs_core::pus::event::Subservices; use satrs_core::pus::event_man::{EventRequest, EventRequestWithToken}; +use satrs_core::pus::hk; use satrs_core::pus::verification::{ FailParams, StdVerifReporterWithSender, TcStateAccepted, VerificationToken, }; use satrs_core::res_code::ResultU16; use satrs_core::tmtc::tm_helper::PusTmWithCdsShortHelper; -use satrs_core::tmtc::PusServiceProvider; -use satrs_example::{INVALID_PUS_SERVICE, INVALID_PUS_SUBSERVICE, NOT_ENOUGH_APP_DATA}; +use satrs_core::tmtc::{AddressableId, PusServiceProvider}; +use satrs_example::{hk_err, tmtc_err}; use spacepackets::ecss::PusPacket; use spacepackets::tc::PusTc; use spacepackets::time::cds::TimeProvider; use spacepackets::time::TimeWriter; use spacepackets::SpHeader; -use std::sync::mpsc; +use std::collections::HashMap; +use std::sync::mpsc::Sender; pub struct PusReceiver { pub tm_helper: PusTmWithCdsShortHelper, - pub tm_tx: mpsc::Sender, + pub tm_tx: Sender, pub tm_store: TmStore, pub verif_reporter: StdVerifReporterWithSender, - event_request_tx: mpsc::Sender, + event_request_tx: Sender, + request_map: HashMap>, stamper: TimeProvider, time_stamp: [u8; 7], } @@ -30,10 +35,11 @@ pub struct PusReceiver { impl PusReceiver { pub fn new( apid: u16, - tm_tx: mpsc::Sender, + tm_tx: Sender, tm_store: TmStore, verif_reporter: StdVerifReporterWithSender, - event_request_tx: mpsc::Sender, + event_request_tx: Sender, + request_map: HashMap>, ) -> Self { Self { tm_helper: PusTmWithCdsShortHelper::new(apid), @@ -41,7 +47,8 @@ impl PusReceiver { tm_store, verif_reporter, event_request_tx, - stamper: TimeProvider::default(), + request_map, + stamper: TimeProvider::new_with_u16_days(0, 0), time_stamp: [0; 7], } } @@ -65,13 +72,15 @@ impl PusServiceProvider for PusReceiver { if service == 17 { self.handle_test_service(pus_tc, accepted_token); } else if service == 5 { - self.handle_event_service(pus_tc, accepted_token); + self.handle_event_request(pus_tc, accepted_token); + } else if service == 3 { + self.handle_hk_request(pus_tc, accepted_token); } else { self.update_time_stamp(); self.verif_reporter .start_failure( accepted_token, - FailParams::new(&self.time_stamp, &INVALID_PUS_SERVICE, None), + FailParams::new(&self.time_stamp, &tmtc_err::INVALID_PUS_SERVICE, None), ) .expect("Start failure verification failed") } @@ -81,7 +90,7 @@ impl PusServiceProvider for PusReceiver { impl PusReceiver { fn handle_test_service(&mut self, pus_tc: &PusTc, token: VerificationToken) { - if pus_tc.subservice() == 1 { + if PusPacket::subservice(pus_tc) == 1 { println!("Received PUS ping command TC[17,1]"); println!("Sending ping reply PUS TM[17,2]"); let ping_reply = self.tm_helper.create_pus_tm_timestamp_now(17, 2, None); @@ -101,7 +110,7 @@ impl PusReceiver { self.verif_reporter .start_failure( token, - FailParams::new(&self.time_stamp, &INVALID_PUS_SUBSERVICE, None), + FailParams::new(&self.time_stamp, &tmtc_err::INVALID_PUS_SUBSERVICE, None), ) .expect("Sending start failure TM failed"); } @@ -116,7 +125,75 @@ impl PusReceiver { .expect("Writing timestamp failed"); } - fn handle_event_service(&mut self, pus_tc: &PusTc, token: VerificationToken) { + fn handle_hk_request(&mut self, pus_tc: &PusTc, token: VerificationToken) { + if pus_tc.user_data().is_none() { + self.update_time_stamp(); + self.verif_reporter + .start_failure( + token, + FailParams::new(&self.time_stamp, &tmtc_err::NOT_ENOUGH_APP_DATA, None), + ) + .expect("Sending start failure TM failed"); + return; + } + let user_data = pus_tc.user_data().unwrap(); + if user_data.len() < 8 { + let err = if user_data.len() < 4 { + &hk_err::TARGET_ID_MISSING + } else { + &hk_err::UNIQUE_ID_MISSING + }; + self.update_time_stamp(); + self.verif_reporter + .start_failure(token, FailParams::new(&self.time_stamp, err, None)) + .expect("Sending start failure TM failed"); + return; + } + let addressable_id = AddressableId::from_raw_be(user_data).unwrap(); + if !self.request_map.contains_key(&addressable_id.target_id) { + self.update_time_stamp(); + self.verif_reporter + .start_failure( + token, + FailParams::new(&self.time_stamp, &hk_err::UNKNOWN_TARGET_ID, None), + ) + .expect("Sending start failure TM failed"); + return; + } + let send_request = |request: HkRequest| { + let sender = self.request_map.get(&addressable_id.target_id).unwrap(); + sender + .send(RequestWithToken(Request::HkRequest(request), token)) + .unwrap_or_else(|_| panic!("Sending HK request {:?} failed", request)); + }; + if PusPacket::subservice(pus_tc) == hk::Subservice::TcEnableGeneration as u8 { + send_request(HkRequest::Enable(addressable_id.unique_id)); + } else if PusPacket::subservice(pus_tc) == hk::Subservice::TcDisableGeneration as u8 { + send_request(HkRequest::Disable(addressable_id.unique_id)); + } else if PusPacket::subservice(pus_tc) == hk::Subservice::TcGenerateOneShotHk as u8 { + send_request(HkRequest::OneShot(addressable_id.unique_id)); + } else if PusPacket::subservice(pus_tc) == hk::Subservice::TcModifyCollectionInterval as u8 + { + if user_data.len() < 12 { + self.update_time_stamp(); + self.verif_reporter + .start_failure( + token, + FailParams::new( + &self.time_stamp, + &hk_err::COLLECTION_INTERVAL_MISSING, + None, + ), + ) + .expect("Sending start failure TM failed"); + return; + } + send_request(HkRequest::ModifyCollectionInterval( + CollectionIntervalFactor::from_be_bytes(user_data[8..12].try_into().unwrap()), + )); + } + } + fn handle_event_request(&mut self, pus_tc: &PusTc, token: VerificationToken) { let send_start_failure = |verif_reporter: &mut StdVerifReporterWithSender, timestamp: &[u8; 7], failure_code: &ResultU16, @@ -139,7 +216,7 @@ impl PusReceiver { send_start_failure( &mut self.verif_reporter, &self.time_stamp, - &NOT_ENOUGH_APP_DATA, + &tmtc_err::NOT_ENOUGH_APP_DATA, None, ); return; @@ -150,7 +227,7 @@ impl PusReceiver { send_start_failure( &mut self.verif_reporter, &self.time_stamp, - &NOT_ENOUGH_APP_DATA, + &tmtc_err::NOT_ENOUGH_APP_DATA, None, ); return; @@ -182,7 +259,7 @@ impl PusReceiver { send_start_failure( &mut self.verif_reporter, &self.time_stamp, - &INVALID_PUS_SUBSERVICE, + &tmtc_err::INVALID_PUS_SUBSERVICE, None, ); } diff --git a/satrs-example/src/requests.rs b/satrs-example/src/requests.rs new file mode 100644 index 0000000..cac2277 --- /dev/null +++ b/satrs-example/src/requests.rs @@ -0,0 +1,10 @@ +use crate::hk::HkRequest; +use satrs_core::pus::verification::{TcStateAccepted, VerificationToken}; + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum Request { + HkRequest(HkRequest), +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub struct RequestWithToken(pub Request, pub VerificationToken); diff --git a/satrs-example/src/tmtc.rs b/satrs-example/src/tmtc.rs index 03d0db0..e63502a 100644 --- a/satrs-example/src/tmtc.rs +++ b/satrs-example/src/tmtc.rs @@ -1,6 +1,7 @@ use satrs_core::events::EventU32; use satrs_core::hal::host::udp_server::{ReceiveResult, UdpTcServer}; use satrs_core::params::Params; +use std::collections::HashMap; use std::net::SocketAddr; use std::sync::mpsc; use std::sync::mpsc::Sender; @@ -9,6 +10,7 @@ use std::time::Duration; use crate::ccsds::CcsdsReceiver; use crate::pus::PusReceiver; +use crate::requests::RequestWithToken; use crate::UdpTmtcServer; use satrs_core::pool::{SharedPool, StoreAddr}; use satrs_core::pus::event_man::EventRequestWithToken; @@ -23,6 +25,7 @@ pub struct CoreTmtcArgs { pub tm_sender: Sender, pub event_sender: Sender<(EventU32, Option)>, pub event_request_tx: Sender, + pub request_map: HashMap>, } #[derive(Clone)] @@ -53,6 +56,7 @@ pub fn core_tmtc_task( args.tm_store.clone(), verif_reporter, args.event_request_tx, + args.request_map, ); let pus_distributor = PusDistributor::new(Box::new(pus_receiver)); let ccsds_receiver = CcsdsReceiver { diff --git a/spacepackets b/spacepackets index db471e3..9b091e3 160000 --- a/spacepackets +++ b/spacepackets @@ -1 +1 @@ -Subproject commit db471e313c92c313d270d5a6f06c0414abb5fae3 +Subproject commit 9b091e3a3a6f599b093c96327751bcf1bc911ca1