Merge branch 'mueller_add_hk_in_example'
This commit is contained in:
commit
f109d59d56
@ -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 = []
|
||||
|
||||
|
@ -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]
|
||||
/// and the listener table will be the [DefaultListenerTableProvider].
|
||||
pub fn new(event_receiver: Box<dyn EventReceiver<Event, AuxDataProvider>>) -> Self {
|
||||
let listener_table = Box::new(DefaultListenerTableProvider::default());
|
||||
let sender_table =
|
||||
Box::new(DefaultSenderTableProvider::<E, Event, AuxDataProvider>::default());
|
||||
let listener_table: Box<DefaultListenerTableProvider> = Box::default();
|
||||
let sender_table: Box<DefaultSenderTableProvider<E, Event, AuxDataProvider>> =
|
||||
Box::default();
|
||||
Self::new_custom_tables(listener_table, sender_table, event_receiver)
|
||||
}
|
||||
}
|
||||
|
@ -136,17 +136,14 @@ impl<RAW: ToBeBytes, GID, UID> EventBase<RAW, GID, UID> {
|
||||
impl EventBase<u32, u16, u16> {
|
||||
#[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<u16, u8, u8> {
|
||||
#[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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
8
satrs-core/src/pus/hk.rs
Normal file
8
satrs-core/src/pus/hk.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Subservice {
|
||||
TcEnableGeneration = 5,
|
||||
TcDisableGeneration = 6,
|
||||
TmHkPacket = 25,
|
||||
TcGenerateOneShotHk = 27,
|
||||
TcModifyCollectionInterval = 31,
|
||||
}
|
@ -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.
|
||||
|
@ -569,7 +569,7 @@ impl VerificationReporterBasic {
|
||||
) -> Result<PusTm, EcssTmError<E>> {
|
||||
let mut source_data_len = size_of::<u32>();
|
||||
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<PusTm, EcssTmError<E>> {
|
||||
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(),
|
||||
|
@ -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<Self, ByteConversionError> {
|
||||
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.
|
||||
|
@ -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():
|
||||
|
15
satrs-example/src/hk.rs
Normal file
15
satrs-example/src/hk.rs
Normal 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),
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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<StoreAddr>,
|
||||
@ -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::<RequestWithToken>();
|
||||
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]) {
|
||||
|
@ -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<StoreAddr>,
|
||||
pub tm_tx: Sender<StoreAddr>,
|
||||
pub tm_store: TmStore,
|
||||
pub verif_reporter: StdVerifReporterWithSender,
|
||||
event_request_tx: mpsc::Sender<EventRequestWithToken>,
|
||||
event_request_tx: Sender<EventRequestWithToken>,
|
||||
request_map: HashMap<u32, Sender<RequestWithToken>>,
|
||||
stamper: TimeProvider,
|
||||
time_stamp: [u8; 7],
|
||||
}
|
||||
@ -30,10 +35,11 @@ pub struct PusReceiver {
|
||||
impl PusReceiver {
|
||||
pub fn new(
|
||||
apid: u16,
|
||||
tm_tx: mpsc::Sender<StoreAddr>,
|
||||
tm_tx: Sender<StoreAddr>,
|
||||
tm_store: TmStore,
|
||||
verif_reporter: StdVerifReporterWithSender,
|
||||
event_request_tx: mpsc::Sender<EventRequestWithToken>,
|
||||
event_request_tx: Sender<EventRequestWithToken>,
|
||||
request_map: HashMap<u32, Sender<RequestWithToken>>,
|
||||
) -> 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<TcStateAccepted>) {
|
||||
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<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,
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
10
satrs-example/src/requests.rs
Normal file
10
satrs-example/src/requests.rs
Normal 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>);
|
@ -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<StoreAddr>,
|
||||
pub event_sender: Sender<(EventU32, Option<Params>)>,
|
||||
pub event_request_tx: Sender<EventRequestWithToken>,
|
||||
pub request_map: HashMap<u32, Sender<RequestWithToken>>,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit db471e313c92c313d270d5a6f06c0414abb5fae3
|
||||
Subproject commit 9b091e3a3a6f599b093c96327751bcf1bc911ca1
|
Loading…
Reference in New Issue
Block a user