Merge branch 'mueller_add_hk_in_example'

This commit is contained in:
Robin Müller 2022-12-21 10:25:26 +01:00
commit f109d59d56
16 changed files with 292 additions and 75 deletions

View File

@ -32,6 +32,7 @@ default-features = false
[dependencies.serde] [dependencies.serde]
version = "1.0" version = "1.0"
default-features = false default-features = false
optional = true
[dependencies.spacepackets] [dependencies.spacepackets]
path = "../spacepackets" path = "../spacepackets"
@ -50,6 +51,7 @@ version = "1.0"
default = ["std"] default = ["std"]
std = ["downcast-rs/std", "alloc", "bus", "postcard/use-std", "crossbeam-channel/std", "serde/std"] std = ["downcast-rs/std", "alloc", "bus", "postcard/use-std", "crossbeam-channel/std", "serde/std"]
alloc = ["serde/alloc"] alloc = ["serde/alloc"]
serde = ["dep:serde"]
heapless = [] heapless = []
doc-images = [] doc-images = []

View File

@ -211,9 +211,9 @@ impl<E: 'static, Event: GenericEvent + Copy + 'static, AuxDataProvider: Clone +
/// Create an event manager where the sender table will be the [DefaultSenderTableProvider] /// Create an event manager where the sender table will be the [DefaultSenderTableProvider]
/// and the listener table will be the [DefaultListenerTableProvider]. /// and the listener table will be the [DefaultListenerTableProvider].
pub fn new(event_receiver: Box<dyn EventReceiver<Event, AuxDataProvider>>) -> Self { pub fn new(event_receiver: Box<dyn EventReceiver<Event, AuxDataProvider>>) -> Self {
let listener_table = Box::new(DefaultListenerTableProvider::default()); let listener_table: Box<DefaultListenerTableProvider> = Box::default();
let sender_table = let sender_table: Box<DefaultSenderTableProvider<E, Event, AuxDataProvider>> =
Box::new(DefaultSenderTableProvider::<E, Event, AuxDataProvider>::default()); Box::default();
Self::new_custom_tables(listener_table, sender_table, event_receiver) Self::new_custom_tables(listener_table, sender_table, event_receiver)
} }
} }

View File

@ -136,17 +136,14 @@ impl<RAW: ToBeBytes, GID, UID> EventBase<RAW, GID, UID> {
impl EventBase<u32, u16, u16> { impl EventBase<u32, u16, u16> {
#[inline] #[inline]
fn raw(&self) -> u32 { fn raw(&self) -> u32 {
(((self.severity as u32) << 30) | ((self.group_id as u32) << 16) | self.unique_id as u32) ((self.severity as u32) << 30) | ((self.group_id as u32) << 16) | self.unique_id as u32
as u32
} }
} }
impl EventBase<u16, u8, u8> { impl EventBase<u16, u8, u8> {
#[inline] #[inline]
fn raw(&self) -> u16 { fn raw(&self) -> u16 {
(((self.severity as u16) << 14) as u16 ((self.severity as u16) << 14) | ((self.group_id as u16) << 8) | self.unique_id as u16
| ((self.group_id as u16) << 8) as u16
| self.unique_id as u16) as u16
} }
} }

View File

@ -136,7 +136,7 @@ impl StoreAddr {
pub const INVALID_ADDR: u32 = 0xFFFFFFFF; pub const INVALID_ADDR: u32 = 0xFFFFFFFF;
pub fn raw(&self) -> u32 { 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> { fn validate_addr(&self, addr: &StoreAddr) -> Result<(), StoreError> {
let pool_idx = addr.pool_idx as usize; 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( return Err(StoreError::InvalidStoreId(
StoreIdError::InvalidSubpool(addr.pool_idx), StoreIdError::InvalidSubpool(addr.pool_idx),
Some(*addr), Some(*addr),

8
satrs-core/src/pus/hk.rs Normal file
View File

@ -0,0 +1,8 @@
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Subservice {
TcEnableGeneration = 5,
TcDisableGeneration = 6,
TmHkPacket = 25,
TcGenerateOneShotHk = 27,
TcModifyCollectionInterval = 31,
}

View File

@ -12,6 +12,7 @@ use spacepackets::{ByteConversionError, SizeMissmatch};
pub mod event; pub mod event;
pub mod event_man; pub mod event_man;
pub mod hk;
pub mod verification; pub mod verification;
/// Generic error type which is also able to wrap a user send error with the user supplied type E. /// Generic error type which is also able to wrap a user send error with the user supplied type E.

View File

@ -569,7 +569,7 @@ impl VerificationReporterBasic {
) -> Result<PusTm, EcssTmError<E>> { ) -> Result<PusTm, EcssTmError<E>> {
let mut source_data_len = size_of::<u32>(); let mut source_data_len = size_of::<u32>();
if let Some(step) = step { 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)?; source_buffer_large_enough(buf.len(), source_data_len)?;
let mut idx = 0; let mut idx = 0;
@ -577,7 +577,7 @@ impl VerificationReporterBasic {
idx += RequestId::SIZE_AS_BYTES; idx += RequestId::SIZE_AS_BYTES;
if let Some(step) = step { if let Some(step) = step {
// Size check was done beforehand // 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(); .unwrap();
} }
let mut sp_header = SpHeader::tm_unseg(self.apid(), 0, 0).unwrap(); let mut sp_header = SpHeader::tm_unseg(self.apid(), 0, 0).unwrap();
@ -601,10 +601,9 @@ impl VerificationReporterBasic {
params: &'a FailParams, params: &'a FailParams,
) -> Result<PusTm, EcssTmError<E>> { ) -> Result<PusTm, EcssTmError<E>> {
let mut idx = 0; let mut idx = 0;
let mut source_data_len = let mut source_data_len = RequestId::SIZE_AS_BYTES + params.failure_code.byte_width();
RequestId::SIZE_AS_BYTES + params.failure_code.byte_width() as usize;
if let Some(step) = step { 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 { if let Some(failure_data) = params.failure_data {
source_data_len += failure_data.len(); source_data_len += failure_data.len();
@ -614,14 +613,14 @@ impl VerificationReporterBasic {
idx += RequestId::SIZE_AS_BYTES; idx += RequestId::SIZE_AS_BYTES;
if let Some(step) = step { if let Some(step) = step {
// Size check done beforehand // 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(); .unwrap();
idx += step.byte_width() as usize; idx += step.byte_width();
} }
params params
.failure_code .failure_code
.write_to_be_bytes(&mut buf[idx..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() as usize; idx += params.failure_code.byte_width();
if let Some(failure_data) = params.failure_data { if let Some(failure_data) = params.failure_data {
buf[idx..idx + failure_data.len()].copy_from_slice(failure_data); buf[idx..idx + failure_data.len()].copy_from_slice(failure_data);
} }
@ -709,8 +708,8 @@ mod allocmod {
source_data_buf: vec![ source_data_buf: vec![
0; 0;
RequestId::SIZE_AS_BYTES RequestId::SIZE_AS_BYTES
+ cfg.step_field_width as usize + cfg.step_field_width
+ cfg.fail_code_field_width as usize + cfg.fail_code_field_width
+ cfg.max_fail_data_len + cfg.max_fail_data_len
], ],
seq_counter: cfg.seq_counter.clone(), seq_counter: cfg.seq_counter.clone(),

View File

@ -5,10 +5,11 @@
//! directly dispatch received packets to packet listeners based on packet fields like the CCSDS //! 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 //! 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 //! 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}; use downcast_rs::{impl_downcast, Downcast};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use spacepackets::tc::PusTc; use spacepackets::tc::PusTc;
use spacepackets::SpHeader; use spacepackets::{ByteConversionError, SizeMissmatch, SpHeader};
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub mod ccsds_distrib; pub mod ccsds_distrib;
@ -19,24 +20,27 @@ pub mod tm_helper;
pub use ccsds_distrib::{CcsdsDistributor, CcsdsError, CcsdsPacketHandler}; pub use ccsds_distrib::{CcsdsDistributor, CcsdsError, CcsdsPacketHandler};
pub use pus_distrib::{PusDistributor, PusServiceProvider}; pub use pus_distrib::{PusDistributor, PusServiceProvider};
const _RAW_PACKET_ERROR: &str = "raw-tmtc"; #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
const _CCSDS_ERROR: &str = "ccsds-tmtc"; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
const _PUS_ERROR: &str = "pus-tmtc"; pub struct AddressableId {
pub target_id: u32,
pub unique_id: u32,
}
// TODO: A macro for general and unknown errors would be nice impl AddressableId {
const _FROM_BYTES_SLICE_TOO_SMALL_ERROR: FsrcErrorRaw = FsrcErrorRaw::new( pub fn from_raw_be(buf: &[u8]) -> Result<Self, ByteConversionError> {
FsrcGroupIds::Tmtc as u8, if buf.len() < 8 {
0, return Err(ByteConversionError::FromSliceTooSmall(SizeMissmatch {
_RAW_PACKET_ERROR, found: buf.len(),
"FROM_BYTES_SLICE_TOO_SMALL_ERROR", expected: 8,
); }));
}
const _FROM_BYTES_ZEROCOPY_ERROR: FsrcErrorRaw = FsrcErrorRaw::new( Ok(Self {
FsrcGroupIds::Tmtc as u8, target_id: u32::from_be_bytes(buf[0..4].try_into().unwrap()),
1, unique_id: u32::from_be_bytes(buf[4..8].try_into().unwrap()),
_RAW_PACKET_ERROR, })
"FROM_BYTES_ZEROCOPY_ERROR", }
); }
/// Generic trait for object which can receive any telecommands in form of a raw bytestream, with /// Generic trait for object which can receive any telecommands in form of a raw bytestream, with
/// no assumptions about the received protocol. /// no assumptions about the received protocol.

View File

@ -1,5 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Example client for the sat-rs example application""" """Example client for the sat-rs example application"""
import enum
import struct
import sys import sys
import time import time
from typing import Optional from typing import Optional
@ -8,9 +10,9 @@ import tmtccmd
from spacepackets.ecss import PusTelemetry, PusTelecommand, PusVerificator from spacepackets.ecss import PusTelemetry, PusTelecommand, PusVerificator
from spacepackets.ecss.pus_17_test import Service17Tm from spacepackets.ecss.pus_17_test import Service17Tm
from spacepackets.ecss.pus_1_verification import UnpackParams, Service1Tm from spacepackets.ecss.pus_1_verification import UnpackParams, Service1Tm
from spacepackets.util import UnsignedByteField
from tmtccmd import CcsdsTmtcBackend, TcHandlerBase, ProcedureParamsWrapper 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.core.base import BackendRequest
from tmtccmd.pus import VerificationWrapper from tmtccmd.pus import VerificationWrapper
from tmtccmd.tm import CcsdsTmHandler, SpecificApidHandlerBase from tmtccmd.tm import CcsdsTmHandler, SpecificApidHandlerBase
@ -85,6 +87,13 @@ class SatRsConfigHook(TmTcCfgHookBase):
info="PUS Service 17 Test", info="PUS Service 17 Test",
op_code_entry=srv_17, 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 return defs
def perform_mode_operation(self, tmtc_backend: CcsdsTmtcBackend, mode: int): 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) 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): class TcHandler(TcHandlerBase):
def __init__( def __init__(
self, self,
@ -197,17 +224,27 @@ class TcHandler(TcHandlerBase):
) )
def feed_cb(self, helper: ProcedureWrapper, wrapper: FeedWrapper): 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: if helper.proc_type == TcProcedureType.DEFAULT:
def_proc = helper.to_def_procedure() def_proc = helper.to_def_procedure()
service = def_proc.service service = def_proc.service
op_code = def_proc.op_code
if ( if (
service == CoreServiceList.SERVICE_17 service == CoreServiceList.SERVICE_17
or service == CoreServiceList.SERVICE_17_ALT 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) 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(): def main():

15
satrs-example/src/hk.rs Normal file
View File

@ -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),
}

View File

@ -3,14 +3,23 @@ use std::net::Ipv4Addr;
use satrs_mib::res_code::{ResultU16, ResultU16Info}; use satrs_mib::res_code::{ResultU16, ResultU16Info};
use satrs_mib::resultcode; use satrs_mib::resultcode;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum RequestTargetId {
AcsSubsystem = 1,
}
#[derive(Debug)] #[derive(Debug)]
pub enum GroupId { pub enum GroupId {
Tmtc = 0, Tmtc = 0,
Hk = 1,
} }
pub const OBSW_SERVER_ADDR: Ipv4Addr = Ipv4Addr::UNSPECIFIED; pub const OBSW_SERVER_ADDR: Ipv4Addr = Ipv4Addr::UNSPECIFIED;
pub const SERVER_PORT: u16 = 7301; pub const SERVER_PORT: u16 = 7301;
pub mod tmtc_err {
use super::*;
#[resultcode] #[resultcode]
pub const INVALID_PUS_SERVICE: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 0); pub const INVALID_PUS_SERVICE: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 0);
#[resultcode] #[resultcode]
@ -24,3 +33,17 @@ pub const TMTC_RESULTS: &[ResultU16Info] = &[
INVALID_PUS_SUBSERVICE_EXT, INVALID_PUS_SUBSERVICE_EXT,
NOT_ENOUGH_APP_DATA_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);
}

View File

@ -1,7 +1,10 @@
mod ccsds; mod ccsds;
mod hk;
mod pus; mod pus;
mod requests;
mod tmtc; mod tmtc;
use crate::requests::RequestWithToken;
use crate::tmtc::{core_tmtc_task, CoreTmtcArgs, TmStore, PUS_APID}; use crate::tmtc::{core_tmtc_task, CoreTmtcArgs, TmStore, PUS_APID};
use satrs_core::event_man::{ use satrs_core::event_man::{
EventManagerWithMpscQueue, MpscEventReceiver, MpscEventU32SendProvider, SendEventProvider, EventManagerWithMpscQueue, MpscEventReceiver, MpscEventU32SendProvider, SendEventProvider,
@ -19,14 +22,16 @@ use satrs_core::pus::verification::{
use satrs_core::pus::{EcssTmError, EcssTmSender}; use satrs_core::pus::{EcssTmError, EcssTmSender};
use satrs_core::seq_count::SimpleSeqCountProvider; use satrs_core::seq_count::SimpleSeqCountProvider;
use satrs_core::tmtc::CcsdsError; 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::cds::TimeProvider;
use spacepackets::time::TimeWriter; use spacepackets::time::TimeWriter;
use spacepackets::tm::PusTm; use spacepackets::tm::PusTm;
use std::collections::HashMap;
use std::net::{IpAddr, SocketAddr}; use std::net::{IpAddr, SocketAddr};
use std::sync::mpsc::channel; use std::sync::mpsc::{channel, TryRecvError};
use std::sync::{mpsc, Arc, RwLock}; use std::sync::{mpsc, Arc, RwLock};
use std::thread; use std::thread;
use std::time::Duration;
struct TmFunnel { struct TmFunnel {
tm_funnel_rx: mpsc::Receiver<StoreAddr>, tm_funnel_rx: mpsc::Receiver<StoreAddr>,
@ -78,6 +83,7 @@ fn main() {
let sender = MpscVerifSender::new(tm_store.clone(), tm_funnel_tx.clone()); let sender = MpscVerifSender::new(tm_store.clone(), tm_funnel_tx.clone());
let verif_cfg = VerificationReporterCfg::new( let verif_cfg = VerificationReporterCfg::new(
PUS_APID, PUS_APID,
#[allow(clippy::box_default)]
Box::new(SimpleSeqCountProvider::default()), Box::new(SimpleSeqCountProvider::default()),
1, 1,
2, 2,
@ -97,15 +103,21 @@ fn main() {
PusEventDispatcher::new(event_reporter, Box::new(pus_tm_backend)); PusEventDispatcher::new(event_reporter, Box::new(pus_tm_backend));
let (pus_event_man_tx, pus_event_man_rx) = channel(); let (pus_event_man_tx, pus_event_man_rx) = channel();
let pus_event_man_send_provider = MpscEventU32SendProvider::new(1, pus_event_man_tx); 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()); event_man.subscribe_all(pus_event_man_send_provider.id());
let mut request_map = HashMap::new();
let (acs_thread_tx, acs_thread_rx) = channel::<RequestWithToken>();
request_map.insert(RequestTargetId::AcsSubsystem as u32, acs_thread_tx);
// Create clones here to allow move for thread 0 // Create clones here to allow move for thread 0
let core_args = CoreTmtcArgs { let core_args = CoreTmtcArgs {
tm_store: tm_store_helper.clone(), tm_store: tm_store_helper.clone(),
tm_sender: tm_funnel_tx.clone(), tm_sender: tm_funnel_tx.clone(),
event_sender, event_sender,
event_request_tx, event_request_tx,
request_map,
}; };
println!("Starting TMTC task"); println!("Starting TMTC task");
@ -135,7 +147,7 @@ fn main() {
let mut sender = EventTmSender::new(tm_store_helper, tm_funnel_tx); let mut sender = EventTmSender::new(tm_store_helper, tm_funnel_tx);
let mut time_provider = TimeProvider::new_with_u16_days(0, 0); let mut time_provider = TimeProvider::new_with_u16_days(0, 0);
let mut report_completion = |event_req: EventRequestWithToken, timestamp: &[u8]| { let mut report_completion = |event_req: EventRequestWithToken, timestamp: &[u8]| {
reporter1 reporter_event_handler
.completion_success(event_req.token, timestamp) .completion_success(event_req.token, timestamp)
.expect("Sending completion success failed"); .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, &timestamp)
.expect("Sending start success failed");
reporter_aocs
.completion_success(started_token, &timestamp)
.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"); jh0.join().expect("Joining UDP TMTC server thread failed");
jh1.join().expect("Joining TM Funnel thread failed"); jh1.join().expect("Joining TM Funnel thread failed");
jh2.join().expect("Joining Event Manager 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]) { pub fn update_time(time_provider: &mut TimeProvider, timestamp: &mut [u8]) {

View File

@ -1,28 +1,33 @@
use crate::hk::{CollectionIntervalFactor, HkRequest};
use crate::requests::{Request, RequestWithToken};
use crate::tmtc::TmStore; use crate::tmtc::TmStore;
use satrs_core::events::EventU32; use satrs_core::events::EventU32;
use satrs_core::pool::StoreAddr; use satrs_core::pool::StoreAddr;
use satrs_core::pus::event::Subservices; use satrs_core::pus::event::Subservices;
use satrs_core::pus::event_man::{EventRequest, EventRequestWithToken}; use satrs_core::pus::event_man::{EventRequest, EventRequestWithToken};
use satrs_core::pus::hk;
use satrs_core::pus::verification::{ use satrs_core::pus::verification::{
FailParams, StdVerifReporterWithSender, TcStateAccepted, VerificationToken, FailParams, StdVerifReporterWithSender, TcStateAccepted, VerificationToken,
}; };
use satrs_core::res_code::ResultU16; use satrs_core::res_code::ResultU16;
use satrs_core::tmtc::tm_helper::PusTmWithCdsShortHelper; use satrs_core::tmtc::tm_helper::PusTmWithCdsShortHelper;
use satrs_core::tmtc::PusServiceProvider; use satrs_core::tmtc::{AddressableId, PusServiceProvider};
use satrs_example::{INVALID_PUS_SERVICE, INVALID_PUS_SUBSERVICE, NOT_ENOUGH_APP_DATA}; use satrs_example::{hk_err, tmtc_err};
use spacepackets::ecss::PusPacket; use spacepackets::ecss::PusPacket;
use spacepackets::tc::PusTc; use spacepackets::tc::PusTc;
use spacepackets::time::cds::TimeProvider; use spacepackets::time::cds::TimeProvider;
use spacepackets::time::TimeWriter; use spacepackets::time::TimeWriter;
use spacepackets::SpHeader; use spacepackets::SpHeader;
use std::sync::mpsc; use std::collections::HashMap;
use std::sync::mpsc::Sender;
pub struct PusReceiver { pub struct PusReceiver {
pub tm_helper: PusTmWithCdsShortHelper, pub tm_helper: PusTmWithCdsShortHelper,
pub tm_tx: mpsc::Sender<StoreAddr>, pub tm_tx: Sender<StoreAddr>,
pub tm_store: TmStore, pub tm_store: TmStore,
pub verif_reporter: StdVerifReporterWithSender, pub verif_reporter: StdVerifReporterWithSender,
event_request_tx: mpsc::Sender<EventRequestWithToken>, event_request_tx: Sender<EventRequestWithToken>,
request_map: HashMap<u32, Sender<RequestWithToken>>,
stamper: TimeProvider, stamper: TimeProvider,
time_stamp: [u8; 7], time_stamp: [u8; 7],
} }
@ -30,10 +35,11 @@ pub struct PusReceiver {
impl PusReceiver { impl PusReceiver {
pub fn new( pub fn new(
apid: u16, apid: u16,
tm_tx: mpsc::Sender<StoreAddr>, tm_tx: Sender<StoreAddr>,
tm_store: TmStore, tm_store: TmStore,
verif_reporter: StdVerifReporterWithSender, verif_reporter: StdVerifReporterWithSender,
event_request_tx: mpsc::Sender<EventRequestWithToken>, event_request_tx: Sender<EventRequestWithToken>,
request_map: HashMap<u32, Sender<RequestWithToken>>,
) -> Self { ) -> Self {
Self { Self {
tm_helper: PusTmWithCdsShortHelper::new(apid), tm_helper: PusTmWithCdsShortHelper::new(apid),
@ -41,7 +47,8 @@ impl PusReceiver {
tm_store, tm_store,
verif_reporter, verif_reporter,
event_request_tx, event_request_tx,
stamper: TimeProvider::default(), request_map,
stamper: TimeProvider::new_with_u16_days(0, 0),
time_stamp: [0; 7], time_stamp: [0; 7],
} }
} }
@ -65,13 +72,15 @@ impl PusServiceProvider for PusReceiver {
if service == 17 { if service == 17 {
self.handle_test_service(pus_tc, accepted_token); self.handle_test_service(pus_tc, accepted_token);
} else if service == 5 { } 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 { } else {
self.update_time_stamp(); self.update_time_stamp();
self.verif_reporter self.verif_reporter
.start_failure( .start_failure(
accepted_token, 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") .expect("Start failure verification failed")
} }
@ -81,7 +90,7 @@ impl PusServiceProvider for PusReceiver {
impl PusReceiver { impl PusReceiver {
fn handle_test_service(&mut self, pus_tc: &PusTc, token: VerificationToken<TcStateAccepted>) { fn handle_test_service(&mut self, pus_tc: &PusTc, token: VerificationToken<TcStateAccepted>) {
if pus_tc.subservice() == 1 { if PusPacket::subservice(pus_tc) == 1 {
println!("Received PUS ping command TC[17,1]"); println!("Received PUS ping command TC[17,1]");
println!("Sending ping reply PUS TM[17,2]"); println!("Sending ping reply PUS TM[17,2]");
let ping_reply = self.tm_helper.create_pus_tm_timestamp_now(17, 2, None); let ping_reply = self.tm_helper.create_pus_tm_timestamp_now(17, 2, None);
@ -101,7 +110,7 @@ impl PusReceiver {
self.verif_reporter self.verif_reporter
.start_failure( .start_failure(
token, 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"); .expect("Sending start failure TM failed");
} }
@ -116,7 +125,75 @@ impl PusReceiver {
.expect("Writing timestamp failed"); .expect("Writing timestamp failed");
} }
fn handle_event_service(&mut self, pus_tc: &PusTc, token: VerificationToken<TcStateAccepted>) { fn handle_hk_request(&mut self, pus_tc: &PusTc, token: VerificationToken<TcStateAccepted>) {
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<TcStateAccepted>) {
let send_start_failure = |verif_reporter: &mut StdVerifReporterWithSender, let send_start_failure = |verif_reporter: &mut StdVerifReporterWithSender,
timestamp: &[u8; 7], timestamp: &[u8; 7],
failure_code: &ResultU16, failure_code: &ResultU16,
@ -139,7 +216,7 @@ impl PusReceiver {
send_start_failure( send_start_failure(
&mut self.verif_reporter, &mut self.verif_reporter,
&self.time_stamp, &self.time_stamp,
&NOT_ENOUGH_APP_DATA, &tmtc_err::NOT_ENOUGH_APP_DATA,
None, None,
); );
return; return;
@ -150,7 +227,7 @@ impl PusReceiver {
send_start_failure( send_start_failure(
&mut self.verif_reporter, &mut self.verif_reporter,
&self.time_stamp, &self.time_stamp,
&NOT_ENOUGH_APP_DATA, &tmtc_err::NOT_ENOUGH_APP_DATA,
None, None,
); );
return; return;
@ -182,7 +259,7 @@ impl PusReceiver {
send_start_failure( send_start_failure(
&mut self.verif_reporter, &mut self.verif_reporter,
&self.time_stamp, &self.time_stamp,
&INVALID_PUS_SUBSERVICE, &tmtc_err::INVALID_PUS_SUBSERVICE,
None, None,
); );
} }

View File

@ -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<TcStateAccepted>);

View File

@ -1,6 +1,7 @@
use satrs_core::events::EventU32; use satrs_core::events::EventU32;
use satrs_core::hal::host::udp_server::{ReceiveResult, UdpTcServer}; use satrs_core::hal::host::udp_server::{ReceiveResult, UdpTcServer};
use satrs_core::params::Params; use satrs_core::params::Params;
use std::collections::HashMap;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::mpsc; use std::sync::mpsc;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
@ -9,6 +10,7 @@ use std::time::Duration;
use crate::ccsds::CcsdsReceiver; use crate::ccsds::CcsdsReceiver;
use crate::pus::PusReceiver; use crate::pus::PusReceiver;
use crate::requests::RequestWithToken;
use crate::UdpTmtcServer; use crate::UdpTmtcServer;
use satrs_core::pool::{SharedPool, StoreAddr}; use satrs_core::pool::{SharedPool, StoreAddr};
use satrs_core::pus::event_man::EventRequestWithToken; use satrs_core::pus::event_man::EventRequestWithToken;
@ -23,6 +25,7 @@ pub struct CoreTmtcArgs {
pub tm_sender: Sender<StoreAddr>, pub tm_sender: Sender<StoreAddr>,
pub event_sender: Sender<(EventU32, Option<Params>)>, pub event_sender: Sender<(EventU32, Option<Params>)>,
pub event_request_tx: Sender<EventRequestWithToken>, pub event_request_tx: Sender<EventRequestWithToken>,
pub request_map: HashMap<u32, Sender<RequestWithToken>>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -53,6 +56,7 @@ pub fn core_tmtc_task(
args.tm_store.clone(), args.tm_store.clone(),
verif_reporter, verif_reporter,
args.event_request_tx, args.event_request_tx,
args.request_map,
); );
let pus_distributor = PusDistributor::new(Box::new(pus_receiver)); let pus_distributor = PusDistributor::new(Box::new(pus_receiver));
let ccsds_receiver = CcsdsReceiver { let ccsds_receiver = CcsdsReceiver {

@ -1 +1 @@
Subproject commit db471e313c92c313d270d5a6f06c0414abb5fae3 Subproject commit 9b091e3a3a6f599b093c96327751bcf1bc911ca1