PUS Event Generation #17
@ -41,7 +41,7 @@ use std::vec::Vec;
|
|||||||
/// let mut sph = SpHeader::tc(0x02, 0, 0).unwrap();
|
/// let mut sph = SpHeader::tc(0x02, 0, 0).unwrap();
|
||||||
/// let pus_tc = PusTc::new_simple(&mut sph, 17, 1, None, true);
|
/// let pus_tc = PusTc::new_simple(&mut sph, 17, 1, None, true);
|
||||||
/// let len = pus_tc
|
/// let len = pus_tc
|
||||||
/// .write_to(&mut buf)
|
/// .write_to_bytes(&mut buf)
|
||||||
/// .expect("Error writing PUS TC packet");
|
/// .expect("Error writing PUS TC packet");
|
||||||
/// assert_eq!(len, 13);
|
/// assert_eq!(len, 13);
|
||||||
/// let client = UdpSocket::bind("127.0.0.1:7778").expect("Connecting to UDP server failed");
|
/// let client = UdpSocket::bind("127.0.0.1:7778").expect("Connecting to UDP server failed");
|
||||||
@ -166,7 +166,7 @@ mod tests {
|
|||||||
let mut sph = SpHeader::tc(0x02, 0, 0).unwrap();
|
let mut sph = SpHeader::tc(0x02, 0, 0).unwrap();
|
||||||
let pus_tc = PusTc::new_simple(&mut sph, 17, 1, None, true);
|
let pus_tc = PusTc::new_simple(&mut sph, 17, 1, None, true);
|
||||||
let len = pus_tc
|
let len = pus_tc
|
||||||
.write_to(&mut buf)
|
.write_to_bytes(&mut buf)
|
||||||
.expect("Error writing PUS TC packet");
|
.expect("Error writing PUS TC packet");
|
||||||
let client = UdpSocket::bind("127.0.0.1:7778").expect("Connecting to UDP server failed");
|
let client = UdpSocket::bind("127.0.0.1:7778").expect("Connecting to UDP server failed");
|
||||||
client
|
client
|
||||||
|
115
fsrc-core/src/pus/event.rs
Normal file
115
fsrc-core/src/pus/event.rs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
use crate::pus::{source_buffer_large_enough, EcssTmError, EcssTmSender};
|
||||||
|
use spacepackets::ecss::EcssEnumeration;
|
||||||
|
use spacepackets::tm::PusTm;
|
||||||
|
use spacepackets::tm::PusTmSecondaryHeader;
|
||||||
|
use spacepackets::{SpHeader, MAX_APID};
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
pub use allocvec::EventReporterWithVec;
|
||||||
|
|
||||||
|
pub struct EventReporter {
|
||||||
|
msg_count: u16,
|
||||||
|
apid: u16,
|
||||||
|
pub dest_id: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventReporter {
|
||||||
|
pub fn new(apid: u16) -> Option<Self> {
|
||||||
|
if apid > MAX_APID {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(Self {
|
||||||
|
msg_count: 0,
|
||||||
|
dest_id: 0,
|
||||||
|
apid,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn event_info<E>(
|
||||||
|
&mut self,
|
||||||
|
buf: &mut [u8],
|
||||||
|
sender: &mut (impl EcssTmSender<E> + ?Sized),
|
||||||
|
time_stamp: &[u8],
|
||||||
|
event_id: impl EcssEnumeration,
|
||||||
|
aux_data: Option<&[u8]>,
|
||||||
|
) -> Result<(), EcssTmError<E>> {
|
||||||
|
let mut src_data_len = event_id.byte_width();
|
||||||
|
if let Some(aux_data) = aux_data {
|
||||||
|
src_data_len += aux_data.len();
|
||||||
|
}
|
||||||
|
source_buffer_large_enough(buf.len(), src_data_len)?;
|
||||||
|
let mut sp_header = SpHeader::tm(self.apid, 0, 0).unwrap();
|
||||||
|
let sec_header = PusTmSecondaryHeader::new(5, 0, self.msg_count, self.dest_id, time_stamp);
|
||||||
|
let mut current_idx = 0;
|
||||||
|
event_id.write_to_bytes(&mut buf[0..event_id.byte_width()])?;
|
||||||
|
current_idx += event_id.byte_width();
|
||||||
|
if let Some(aux_data) = aux_data {
|
||||||
|
buf[current_idx..current_idx + aux_data.len()].copy_from_slice(aux_data);
|
||||||
|
current_idx += aux_data.len();
|
||||||
|
}
|
||||||
|
let tm = PusTm::new(&mut sp_header, sec_header, Some(&buf[0..current_idx]), true);
|
||||||
|
sender.send_tm(tm)?;
|
||||||
|
self.msg_count += 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
mod allocvec {
|
||||||
|
use super::*;
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
pub struct EventReporterWithVec {
|
||||||
|
source_data_buf: Vec<u8>,
|
||||||
|
pub reporter: EventReporter,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventReporterWithVec {
|
||||||
|
pub fn new(apid: u16, max_event_id_and_aux_data: usize) -> Option<Self> {
|
||||||
|
let reporter = EventReporter::new(apid)?;
|
||||||
|
Some(Self {
|
||||||
|
source_data_buf: vec![0; max_event_id_and_aux_data],
|
||||||
|
reporter,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn event_info<E>(
|
||||||
|
&mut self,
|
||||||
|
sender: &mut (impl EcssTmSender<E> + ?Sized),
|
||||||
|
time_stamp: &[u8],
|
||||||
|
event_id: impl EcssEnumeration,
|
||||||
|
aux_data: Option<&[u8]>,
|
||||||
|
) -> Result<(), EcssTmError<E>> {
|
||||||
|
self.reporter.event_info(
|
||||||
|
self.source_data_buf.as_mut_slice(),
|
||||||
|
sender,
|
||||||
|
time_stamp,
|
||||||
|
event_id,
|
||||||
|
aux_data,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// pub fn event_low_severity<E>(
|
||||||
|
// &mut self,
|
||||||
|
// _sender: &mut (impl EcssTmSender<E> + ?Sized),
|
||||||
|
// _event_id: impl EcssEnumeration,
|
||||||
|
// _aux_data: Option<&[u8]>,
|
||||||
|
// ) {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn event_medium_severity<E>(
|
||||||
|
// &mut self,
|
||||||
|
// _sender: &mut (impl EcssTmSender<E> + ?Sized),
|
||||||
|
// _event_id: impl EcssEnumeration,
|
||||||
|
// _aux_data: Option<&[u8]>,
|
||||||
|
// ) {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn event_high_severity<E>(
|
||||||
|
// &mut self,
|
||||||
|
// _sender: &mut (impl EcssTmSender<E> + ?Sized),
|
||||||
|
// _event_id: impl EcssEnumeration,
|
||||||
|
// _aux_data: Option<&[u8]>,
|
||||||
|
// ) {
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
@ -3,5 +3,52 @@
|
|||||||
//! Currenty includes:
|
//! Currenty includes:
|
||||||
//!
|
//!
|
||||||
//! 1. PUS Verification Service 1 module inside [verification]. Requires [alloc] support.
|
//! 1. PUS Verification Service 1 module inside [verification]. Requires [alloc] support.
|
||||||
#[cfg(feature = "alloc")]
|
use downcast_rs::{impl_downcast, Downcast};
|
||||||
|
use spacepackets::ecss::PusError;
|
||||||
|
use spacepackets::time::TimestampError;
|
||||||
|
use spacepackets::tm::PusTm;
|
||||||
|
use spacepackets::{ByteConversionError, SizeMissmatch};
|
||||||
|
|
||||||
|
pub mod event;
|
||||||
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.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum EcssTmError<E> {
|
||||||
|
/// Errors related to sending the verification telemetry to a TM recipient
|
||||||
|
SendError(E),
|
||||||
|
/// Errors related to the time stamp format of the telemetry
|
||||||
|
TimestampError(TimestampError),
|
||||||
|
/// Errors related to byte conversion, for example insufficient buffer size for given data
|
||||||
|
ByteConversionError(ByteConversionError),
|
||||||
|
/// Errors related to PUS packet format
|
||||||
|
PusError(PusError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> From<ByteConversionError> for EcssTmError<E> {
|
||||||
|
fn from(e: ByteConversionError) -> Self {
|
||||||
|
EcssTmError::ByteConversionError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic trait for a user supplied sender object. This sender object is responsible for sending
|
||||||
|
/// telemetry to a TM sink. The [Downcast] trait
|
||||||
|
/// is implemented to allow passing the sender as a boxed trait object and still retrieve the
|
||||||
|
/// concrete type at a later point.
|
||||||
|
pub trait EcssTmSender<E>: Downcast + Send {
|
||||||
|
fn send_tm(&mut self, tm: PusTm) -> Result<(), EcssTmError<E>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_downcast!(EcssTmSender<E>);
|
||||||
|
|
||||||
|
pub(crate) fn source_buffer_large_enough<E>(cap: usize, len: usize) -> Result<(), EcssTmError<E>> {
|
||||||
|
if len > cap {
|
||||||
|
return Err(EcssTmError::ByteConversionError(
|
||||||
|
ByteConversionError::ToSliceTooSmall(SizeMissmatch {
|
||||||
|
found: cap,
|
||||||
|
expected: len,
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -58,7 +58,7 @@
|
|||||||
//! let mut pus_tc = PusTc::new_simple(&mut space_packet_header, 17, 1, None, true);
|
//! let mut pus_tc = PusTc::new_simple(&mut space_packet_header, 17, 1, None, true);
|
||||||
//! let mut test_buf: [u8; 32] = [0; 32];
|
//! let mut test_buf: [u8; 32] = [0; 32];
|
||||||
//! let mut size = pus_tc
|
//! let mut size = pus_tc
|
||||||
//! .write_to(test_buf.as_mut_slice())
|
//! .write_to_bytes(test_buf.as_mut_slice())
|
||||||
//! .expect("Error writing TC to buffer");
|
//! .expect("Error writing TC to buffer");
|
||||||
//! let tc_slice = &test_buf[0..size];
|
//! let tc_slice = &test_buf[0..size];
|
||||||
//! ccsds_distributor.pass_tc(&tc_slice).expect("Passing TC slice failed");
|
//! ccsds_distributor.pass_tc(&tc_slice).expect("Passing TC slice failed");
|
||||||
@ -66,7 +66,7 @@
|
|||||||
//! // Now pass a packet with an unknown APID to the distributor
|
//! // Now pass a packet with an unknown APID to the distributor
|
||||||
//! pus_tc.set_apid(0x003);
|
//! pus_tc.set_apid(0x003);
|
||||||
//! size = pus_tc
|
//! size = pus_tc
|
||||||
//! .write_to(test_buf.as_mut_slice())
|
//! .write_to_bytes(test_buf.as_mut_slice())
|
||||||
//! .expect("Error writing TC to buffer");
|
//! .expect("Error writing TC to buffer");
|
||||||
//! let tc_slice = &test_buf[0..size];
|
//! let tc_slice = &test_buf[0..size];
|
||||||
//! ccsds_distributor.pass_tc(&tc_slice).expect("Passing TC slice failed");
|
//! ccsds_distributor.pass_tc(&tc_slice).expect("Passing TC slice failed");
|
||||||
@ -201,7 +201,9 @@ pub(crate) mod tests {
|
|||||||
pub fn generate_ping_tc(buf: &mut [u8]) -> &[u8] {
|
pub fn generate_ping_tc(buf: &mut [u8]) -> &[u8] {
|
||||||
let mut sph = SpHeader::tc(0x002, 0x34, 0).unwrap();
|
let mut sph = SpHeader::tc(0x002, 0x34, 0).unwrap();
|
||||||
let pus_tc = PusTc::new_simple(&mut sph, 17, 1, None, true);
|
let pus_tc = PusTc::new_simple(&mut sph, 17, 1, None, true);
|
||||||
let size = pus_tc.write_to(buf).expect("Error writing TC to buffer");
|
let size = pus_tc
|
||||||
|
.write_to_bytes(buf)
|
||||||
|
.expect("Error writing TC to buffer");
|
||||||
assert_eq!(size, 13);
|
assert_eq!(size, 13);
|
||||||
&buf[0..size]
|
&buf[0..size]
|
||||||
}
|
}
|
||||||
@ -314,7 +316,7 @@ pub(crate) mod tests {
|
|||||||
let pus_tc = PusTc::new_simple(&mut sph, 17, 1, None, true);
|
let pus_tc = PusTc::new_simple(&mut sph, 17, 1, None, true);
|
||||||
let mut test_buf: [u8; 32] = [0; 32];
|
let mut test_buf: [u8; 32] = [0; 32];
|
||||||
pus_tc
|
pus_tc
|
||||||
.write_to(test_buf.as_mut_slice())
|
.write_to_bytes(test_buf.as_mut_slice())
|
||||||
.expect("Error writing TC to buffer");
|
.expect("Error writing TC to buffer");
|
||||||
ccsds_distrib.pass_tc(&test_buf).expect("Passing TC failed");
|
ccsds_distrib.pass_tc(&test_buf).expect("Passing TC failed");
|
||||||
let recvd = unknown_packet_queue.lock().unwrap().pop_front();
|
let recvd = unknown_packet_queue.lock().unwrap().pop_front();
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
//! let mut pus_tc = PusTc::new_simple(&mut space_packet_header, 17, 1, None, true);
|
//! let mut pus_tc = PusTc::new_simple(&mut space_packet_header, 17, 1, None, true);
|
||||||
//! let mut test_buf: [u8; 32] = [0; 32];
|
//! let mut test_buf: [u8; 32] = [0; 32];
|
||||||
//! let mut size = pus_tc
|
//! let mut size = pus_tc
|
||||||
//! .write_to(test_buf.as_mut_slice())
|
//! .write_to_bytes(test_buf.as_mut_slice())
|
||||||
//! .expect("Error writing TC to buffer");
|
//! .expect("Error writing TC to buffer");
|
||||||
//! let tc_slice = &test_buf[0..size];
|
//! let tc_slice = &test_buf[0..size];
|
||||||
//!
|
//!
|
||||||
|
@ -25,7 +25,7 @@ const PACKETS_SENT: u8 = 8;
|
|||||||
/// threads have sent the correct expected verification reports
|
/// threads have sent the correct expected verification reports
|
||||||
#[test]
|
#[test]
|
||||||
fn test_shared_reporter() {
|
fn test_shared_reporter() {
|
||||||
let cfg = VerificationReporterCfg::new(TEST_APID, 1, 2, 8);
|
let cfg = VerificationReporterCfg::new(TEST_APID, 1, 2, 8).unwrap();
|
||||||
// Shared pool object to store the verification PUS telemetry
|
// Shared pool object to store the verification PUS telemetry
|
||||||
let pool_cfg = PoolCfg::new(vec![(10, 32), (10, 64), (10, 128), (10, 1024)]);
|
let pool_cfg = PoolCfg::new(vec![(10, 32), (10, 64), (10, 128), (10, 1024)]);
|
||||||
let shared_tm_pool: SharedPool =
|
let shared_tm_pool: SharedPool =
|
||||||
@ -53,14 +53,14 @@ fn test_shared_reporter() {
|
|||||||
let pus_tc_0 = PusTc::new(&mut sph, tc_header, None, true);
|
let pus_tc_0 = PusTc::new(&mut sph, tc_header, None, true);
|
||||||
req_id_0 = RequestId::new(&pus_tc_0);
|
req_id_0 = RequestId::new(&pus_tc_0);
|
||||||
let (addr, mut buf) = tc_guard.free_element(pus_tc_0.len_packed()).unwrap();
|
let (addr, mut buf) = tc_guard.free_element(pus_tc_0.len_packed()).unwrap();
|
||||||
pus_tc_0.write_to(&mut buf).unwrap();
|
pus_tc_0.write_to_bytes(&mut buf).unwrap();
|
||||||
tx_tc_0.send(addr).unwrap();
|
tx_tc_0.send(addr).unwrap();
|
||||||
let mut sph = SpHeader::tc(TEST_APID, 1, 0).unwrap();
|
let mut sph = SpHeader::tc(TEST_APID, 1, 0).unwrap();
|
||||||
let tc_header = PusTcSecondaryHeader::new_simple(5, 1);
|
let tc_header = PusTcSecondaryHeader::new_simple(5, 1);
|
||||||
let pus_tc_1 = PusTc::new(&mut sph, tc_header, None, true);
|
let pus_tc_1 = PusTc::new(&mut sph, tc_header, None, true);
|
||||||
req_id_1 = RequestId::new(&pus_tc_1);
|
req_id_1 = RequestId::new(&pus_tc_1);
|
||||||
let (addr, mut buf) = tc_guard.free_element(pus_tc_0.len_packed()).unwrap();
|
let (addr, mut buf) = tc_guard.free_element(pus_tc_0.len_packed()).unwrap();
|
||||||
pus_tc_1.write_to(&mut buf).unwrap();
|
pus_tc_1.write_to_bytes(&mut buf).unwrap();
|
||||||
tx_tc_1.send(addr).unwrap();
|
tx_tc_1.send(addr).unwrap();
|
||||||
}
|
}
|
||||||
let verif_sender_0 = thread::spawn(move || {
|
let verif_sender_0 = thread::spawn(move || {
|
||||||
|
@ -18,7 +18,9 @@ fn main() {
|
|||||||
"Packing and sending PUS ping command TC[17,1] with request ID {}",
|
"Packing and sending PUS ping command TC[17,1] with request ID {}",
|
||||||
tc_req_id
|
tc_req_id
|
||||||
);
|
);
|
||||||
let size = pus_tc.write_to(&mut buf).expect("Creating PUS TC failed");
|
let size = pus_tc
|
||||||
|
.write_to_bytes(&mut buf)
|
||||||
|
.expect("Creating PUS TC failed");
|
||||||
client
|
client
|
||||||
.send_to(&buf[0..size], &addr)
|
.send_to(&buf[0..size], &addr)
|
||||||
.expect(&*format!("Sending to {:?} failed", addr));
|
.expect(&*format!("Sending to {:?} failed", addr));
|
||||||
|
@ -39,7 +39,7 @@ fn main() {
|
|||||||
let (tm_funnel_tx, tm_funnel_rx) = mpsc::channel();
|
let (tm_funnel_tx, tm_funnel_rx) = mpsc::channel();
|
||||||
let (tm_server_tx, tm_server_rx) = mpsc::channel();
|
let (tm_server_tx, tm_server_rx) = mpsc::channel();
|
||||||
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(PUS_APID, 1, 2, 8);
|
let verif_cfg = VerificationReporterCfg::new(PUS_APID, 1, 2, 8).unwrap();
|
||||||
let reporter_with_sender_0 = Arc::new(Mutex::new(VerificationReporterWithSender::new(
|
let reporter_with_sender_0 = Arc::new(Mutex::new(VerificationReporterWithSender::new(
|
||||||
verif_cfg,
|
verif_cfg,
|
||||||
Box::new(sender),
|
Box::new(sender),
|
||||||
|
@ -24,7 +24,7 @@ impl TmStore {
|
|||||||
let mut pg = self.pool.write().expect("Error locking TM store");
|
let mut pg = self.pool.write().expect("Error locking TM store");
|
||||||
let (addr, buf) = pg.free_element(pus_tm.len_packed()).expect("Store error");
|
let (addr, buf) = pg.free_element(pus_tm.len_packed()).expect("Store error");
|
||||||
pus_tm
|
pus_tm
|
||||||
.write_to(buf)
|
.write_to_bytes(buf)
|
||||||
.expect("Writing PUS TM to store failed");
|
.expect("Writing PUS TM to store failed");
|
||||||
addr
|
addr
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 94489da00323dc6caf24e05e240c80fc10b5d8cc
|
Subproject commit fe1a30327bcc9a914cd2695b6af74b869a8b23a2
|
Loading…
Reference in New Issue
Block a user