Implementation of scheduler in pus and tmtc handler #29

Merged
muellerr merged 13 commits from pus_schedule_implementation into main 2023-02-01 13:40:49 +01:00
11 changed files with 127 additions and 77 deletions
Showing only changes of commit ebc2330747 - Show all commits

View File

@ -13,8 +13,8 @@ categories = ["aerospace", "aerospace::space-protocols", "no-std", "hardware-sup
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
delegate = "0.8"
paste = "1.0"
delegate = ">=0.8, <0.10"
paste = "1"
embed-doc-image = "0.1"
[dependencies.dyn-clone]
@ -53,7 +53,7 @@ default-features = false
optional = true
[dependencies.spacepackets]
version = "0.5.1"
version = "0.5.2"
# path = "../spacepackets"
# git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git"
# rev = "..."

View File

@ -153,10 +153,10 @@ impl Display for StoreIdError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
StoreIdError::InvalidSubpool(pool) => {
write!(f, "invalid subpool, index: {}", pool)
write!(f, "invalid subpool, index: {pool}")
}
StoreIdError::InvalidPacketIdx(packet_idx) => {
write!(f, "invalid packet index: {}", packet_idx)
write!(f, "invalid packet index: {packet_idx}")
}
}
}
@ -183,19 +183,19 @@ impl Display for StoreError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
StoreError::DataTooLarge(size) => {
write!(f, "data to store with size {} is too large", size)
write!(f, "data to store with size {size} is too large")
}
StoreError::StoreFull(u16) => {
write!(f, "store is too full. index for full subpool: {}", u16)
write!(f, "store is too full. index for full subpool: {u16}")
}
StoreError::InvalidStoreId(id_e, addr) => {
write!(f, "invalid store ID: {}, address: {:?}", id_e, addr)
write!(f, "invalid store ID: {id_e}, address: {addr:?}")
}
StoreError::DataDoesNotExist(addr) => {
write!(f, "no data exists at address {:?}", addr)
write!(f, "no data exists at address {addr:?}")
}
StoreError::InternalError(e) => {
write!(f, "internal error: {}", e)
write!(f, "internal error: {e}")
}
}
}
@ -330,14 +330,12 @@ impl LocalPool {
fn write(&mut self, addr: &StoreAddr, data: &[u8]) -> Result<(), StoreError> {
let packet_pos = self.raw_pos(addr).ok_or_else(|| {
StoreError::InternalError(format!(
"write: Error in raw_pos func with address {:?}",
addr
"write: Error in raw_pos func with address {addr:?}"
))
})?;
let subpool = self.pool.get_mut(addr.pool_idx as usize).ok_or_else(|| {
StoreError::InternalError(format!(
"write: Error retrieving pool slice with address {:?}",
addr
"write: Error retrieving pool slice with address {addr:?}"
))
})?;
let pool_slice = &mut subpool[packet_pos..packet_pos + data.len()];

View File

@ -522,9 +522,9 @@ impl VerificationReporterCore {
)
}
pub fn send_acceptance_success<'src_data, E>(
pub fn send_acceptance_success<E>(
&self,
mut sendable: VerificationSendable<'src_data, TcStateNone, VerifSuccess>,
mut sendable: VerificationSendable<'_, TcStateNone, VerifSuccess>,
seq_counter: &(impl SequenceCountProviderCore<u16> + ?Sized),
sender: &mut (impl EcssTmSenderCore<Error = E> + ?Sized),
) -> Result<VerificationToken<TcStateAccepted>, VerificationOrSendErrorWithToken<E, TcStateNone>>
@ -535,9 +535,9 @@ impl VerificationReporterCore {
Ok(sendable.send_success_acceptance_success(Some(seq_counter)))
}
pub fn send_acceptance_failure<'src_data, E>(
pub fn send_acceptance_failure<E>(
&self,
mut sendable: VerificationSendable<'src_data, TcStateNone, VerifFailure>,
mut sendable: VerificationSendable<'_, TcStateNone, VerifFailure>,
seq_counter: &(impl SequenceCountProviderCore<u16> + ?Sized),
sender: &mut (impl EcssTmSenderCore<Error = E> + ?Sized),
) -> Result<(), VerificationOrSendErrorWithToken<E, TcStateNone>> {
@ -591,9 +591,9 @@ impl VerificationReporterCore {
)
}
pub fn send_start_success<'src_data, E>(
pub fn send_start_success<E>(
&self,
mut sendable: VerificationSendable<'src_data, TcStateAccepted, VerifSuccess>,
mut sendable: VerificationSendable<'_, TcStateAccepted, VerifSuccess>,
seq_counter: &(impl SequenceCountProviderCore<u16> + ?Sized),
sender: &mut (impl EcssTmSenderCore<Error = E> + ?Sized),
) -> Result<
@ -630,9 +630,9 @@ impl VerificationReporterCore {
)
}
pub fn send_start_failure<'src_data, E>(
pub fn send_start_failure<E>(
&self,
mut sendable: VerificationSendable<'src_data, TcStateAccepted, VerifFailure>,
mut sendable: VerificationSendable<'_, TcStateAccepted, VerifFailure>,
seq_counter: &(impl SequenceCountProviderCore<u16> + ?Sized),
sender: &mut (impl EcssTmSenderCore<Error = E> + ?Sized),
) -> Result<(), VerificationOrSendErrorWithToken<E, TcStateAccepted>> {
@ -741,9 +741,9 @@ impl VerificationReporterCore {
)
}
pub fn send_step_or_completion_success<'src_data, E>(
pub fn send_step_or_completion_success<E>(
&self,
mut sendable: VerificationSendable<'src_data, TcStateStarted, VerifSuccess>,
mut sendable: VerificationSendable<'_, TcStateStarted, VerifSuccess>,
seq_counter: &(impl SequenceCountProviderCore<u16> + ?Sized),
sender: &mut (impl EcssTmSenderCore<Error = E> + ?Sized),
) -> Result<(), VerificationOrSendErrorWithToken<E, TcStateStarted>> {
@ -754,9 +754,9 @@ impl VerificationReporterCore {
Ok(())
}
pub fn send_step_or_completion_failure<'src_data, E>(
pub fn send_step_or_completion_failure<E>(
&self,
mut sendable: VerificationSendable<'src_data, TcStateStarted, VerifFailure>,
mut sendable: VerificationSendable<'_, TcStateStarted, VerifFailure>,
seq_counter: &(impl SequenceCountProviderCore<u16> + ?Sized),
sender: &mut (impl EcssTmSenderCore<Error = E> + ?Sized),
) -> Result<(), VerificationOrSendErrorWithToken<E, TcStateStarted>> {

View File

@ -86,8 +86,11 @@
//! ```
use crate::tmtc::{ReceivesCcsdsTc, ReceivesTcCore};
use alloc::boxed::Box;
use core::fmt::{Display, Formatter};
use downcast_rs::Downcast;
use spacepackets::{ByteConversionError, CcsdsPacket, SizeMissmatch, SpHeader};
#[cfg(feature = "std")]
use std::error::Error;
/// Generic trait for a handler or dispatcher object handling CCSDS packets.
///
@ -99,7 +102,7 @@ use spacepackets::{ByteConversionError, CcsdsPacket, SizeMissmatch, SpHeader};
/// This trait automatically implements the [downcast_rs::Downcast] to allow a more convenient API
/// to cast trait objects back to their concrete type after the handler was passed to the
/// distributor.
pub trait CcsdsPacketHandler: Downcast + Send {
pub trait CcsdsPacketHandler: Downcast {
type Error;
fn valid_apids(&self) -> &'static [u16];
@ -114,18 +117,46 @@ pub trait CcsdsPacketHandler: Downcast + Send {
downcast_rs::impl_downcast!(CcsdsPacketHandler assoc Error);
pub trait SendableCcsdsPacketHandler: CcsdsPacketHandler + Send {}
impl<T: CcsdsPacketHandler + Send> SendableCcsdsPacketHandler for T {}
downcast_rs::impl_downcast!(SendableCcsdsPacketHandler assoc Error);
/// The CCSDS distributor dispatches received CCSDS packets to a user provided packet handler.
///
/// The passed APID handler is required to be [Send]able to allow more ergonomic usage with
/// threads.
pub struct CcsdsDistributor<E> {
/// User provided APID handler stored as a generic trait object.
/// It can be cast back to the original concrete type using the [Self::apid_handler_ref] or
/// the [Self::apid_handler_mut] method.
pub apid_handler: Box<dyn CcsdsPacketHandler<Error = E>>,
pub apid_handler: Box<dyn SendableCcsdsPacketHandler<Error = E>>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CcsdsError<E> {
CustomError(E),
PacketError(ByteConversionError),
ByteConversionError(ByteConversionError),
}
impl<E: Display> Display for CcsdsError<E> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
Self::CustomError(e) => write!(f, "{e}"),
Self::ByteConversionError(e) => write!(f, "{e}"),
}
}
}
#[cfg(feature = "std")]
impl<E: Error> Error for CcsdsError<E> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::CustomError(e) => e.source(),
Self::ByteConversionError(e) => e.source(),
}
}
}
impl<E: 'static> ReceivesCcsdsTc for CcsdsDistributor<E> {
@ -141,7 +172,7 @@ impl<E: 'static> ReceivesTcCore for CcsdsDistributor<E> {
fn pass_tc(&mut self, tc_raw: &[u8]) -> Result<(), Self::Error> {
if tc_raw.len() < 7 {
return Err(CcsdsError::PacketError(
return Err(CcsdsError::ByteConversionError(
ByteConversionError::FromSliceTooSmall(SizeMissmatch {
found: tc_raw.len(),
expected: 7,
@ -149,26 +180,26 @@ impl<E: 'static> ReceivesTcCore for CcsdsDistributor<E> {
));
}
let (sp_header, _) =
SpHeader::from_be_bytes(tc_raw).map_err(|e| CcsdsError::PacketError(e))?;
SpHeader::from_be_bytes(tc_raw).map_err(|e| CcsdsError::ByteConversionError(e))?;
self.dispatch_ccsds(&sp_header, tc_raw)
}
}
impl<E: 'static> CcsdsDistributor<E> {
pub fn new(apid_handler: Box<dyn CcsdsPacketHandler<Error = E>>) -> Self {
pub fn new(apid_handler: Box<dyn SendableCcsdsPacketHandler<Error = E>>) -> Self {
CcsdsDistributor { apid_handler }
}
/// This function can be used to retrieve a reference to the concrete instance of the APID
/// handler after it was passed to the distributor. See the
/// [module documentation][crate::tmtc::ccsds_distrib] for an fsrc-example.
pub fn apid_handler_ref<T: CcsdsPacketHandler<Error = E>>(&self) -> Option<&T> {
pub fn apid_handler_ref<T: SendableCcsdsPacketHandler<Error = E>>(&self) -> Option<&T> {
self.apid_handler.downcast_ref::<T>()
}
/// This function can be used to retrieve a mutable reference to the concrete instance of the
/// APID handler after it was passed to the distributor.
pub fn apid_handler_mut<T: CcsdsPacketHandler<Error = E>>(&mut self) -> Option<&mut T> {
pub fn apid_handler_mut<T: SendableCcsdsPacketHandler<Error = E>>(&mut self) -> Option<&mut T> {
self.apid_handler.downcast_mut::<T>()
}

View File

@ -63,19 +63,20 @@ impl AddressableId {
/// This trait is implemented by both the [crate::tmtc::pus_distrib::PusDistributor] and the
/// [crate::tmtc::ccsds_distrib::CcsdsDistributor] which allows to pass the respective packets in
/// raw byte format into them.
pub trait ReceivesTcCore: Send {
pub trait ReceivesTcCore {
type Error;
fn pass_tc(&mut self, tc_raw: &[u8]) -> Result<(), Self::Error>;
}
/// Extension trait of [ReceivesTcCore] which allows downcasting by implementing [Downcast]
/// Extension trait of [ReceivesTcCore] which allows downcasting by implementing [Downcast] and
/// is also sendable.
#[cfg(feature = "alloc")]
pub trait ReceivesTc: ReceivesTcCore + Downcast {}
pub trait ReceivesTc: ReceivesTcCore + Downcast + Send {}
/// Blanket implementation to automatically implement [ReceivesTc] when the [alloc] feature
/// is enabled.
#[cfg(feature = "alloc")]
impl<T> ReceivesTc for T where T: ReceivesTcCore + 'static {}
impl<T> ReceivesTc for T where T: ReceivesTcCore + Send + 'static {}
#[cfg(feature = "alloc")]
impl_downcast!(ReceivesTc assoc Error);

View File

@ -62,12 +62,15 @@
//! ```
use crate::tmtc::{ReceivesCcsdsTc, ReceivesEcssPusTc, ReceivesTcCore};
use alloc::boxed::Box;
use core::fmt::{Display, Formatter};
use downcast_rs::Downcast;
use spacepackets::ecss::{PusError, PusPacket};
use spacepackets::tc::PusTc;
use spacepackets::SpHeader;
#[cfg(feature = "std")]
use std::error::Error;
pub trait PusServiceProvider: Downcast + Send {
pub trait PusServiceProvider: Downcast {
type Error;
fn handle_pus_tc_packet(
&mut self,
@ -78,12 +81,22 @@ pub trait PusServiceProvider: Downcast + Send {
}
downcast_rs::impl_downcast!(PusServiceProvider assoc Error);
pub trait SendablePusServiceProvider: PusServiceProvider + Send {}
impl<T: Send + PusServiceProvider> SendablePusServiceProvider for T {}
downcast_rs::impl_downcast!(SendablePusServiceProvider assoc Error);
/// Generic distributor object which dispatches received packets to a user provided handler.
///
/// This distributor expects the passed trait object to be [Send]able to allow more ergonomic
/// usage with threads.
pub struct PusDistributor<E> {
pub service_provider: Box<dyn PusServiceProvider<Error = E>>,
pub service_provider: Box<dyn SendablePusServiceProvider<Error = E>>,
}
impl<E> PusDistributor<E> {
pub fn new(service_provider: Box<dyn PusServiceProvider<Error = E>>) -> Self {
pub fn new(service_provider: Box<dyn SendablePusServiceProvider<Error = E>>) -> Self {
PusDistributor { service_provider }
}
}
@ -94,6 +107,25 @@ pub enum PusDistribError<E> {
PusError(PusError),
}
impl<E: Display> Display for PusDistribError<E> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
PusDistribError::CustomError(e) => write!(f, "{e}"),
PusDistribError::PusError(e) => write!(f, "{e}"),
}
}
}
#[cfg(feature = "std")]
impl<E: Error> Error for PusDistribError<E> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::CustomError(e) => e.source(),
Self::PusError(e) => e.source(),
}
}
}
impl<E: 'static> ReceivesTcCore for PusDistributor<E> {
type Error = PusDistribError<E>;
fn pass_tc(&mut self, tm_raw: &[u8]) -> Result<(), Self::Error> {
@ -122,11 +154,13 @@ impl<E: 'static> ReceivesEcssPusTc for PusDistributor<E> {
}
impl<E: 'static> PusDistributor<E> {
pub fn service_provider_ref<T: PusServiceProvider<Error = E>>(&self) -> Option<&T> {
pub fn service_provider_ref<T: SendablePusServiceProvider<Error = E>>(&self) -> Option<&T> {
self.service_provider.downcast_ref::<T>()
}
pub fn service_provider_mut<T: PusServiceProvider<Error = E>>(&mut self) -> Option<&mut T> {
pub fn service_provider_mut<T: SendablePusServiceProvider<Error = E>>(
&mut self,
) -> Option<&mut T> {
self.service_provider.downcast_mut::<T>()
}
}

View File

@ -20,14 +20,15 @@ fn threaded_usage() {
});
let jh1 = thread::spawn(move || {
let mut pool_access = shared_clone.write().unwrap();
let addr;
{
addr = rx.recv().expect("Receiving store address failed");
let mut pool_access = shared_clone.write().unwrap();
let pg = PoolGuard::new(pool_access.deref_mut(), addr);
let read_res = pg.read().expect("Reading failed");
assert_eq!(read_res, DUMMY_DATA);
}
let pool_access = shared_clone.read().unwrap();
assert!(!pool_access.has_element_at(&addr).expect("Invalid address"));
});
jh0.join().unwrap();

View File

@ -14,16 +14,13 @@ fn main() {
let pus_tc = PusTc::new_simple(&mut sph, 17, 1, None, true);
let client = UdpSocket::bind("127.0.0.1:7302").expect("Connecting to UDP server failed");
let tc_req_id = RequestId::new(&pus_tc);
println!(
"Packing and sending PUS ping command TC[17,1] with request ID {}",
tc_req_id
);
println!("Packing and sending PUS ping command TC[17,1] with request ID {tc_req_id}");
let size = pus_tc
.write_to_bytes(&mut buf)
.expect("Creating PUS TC failed");
client
.send_to(&buf[0..size], addr)
.unwrap_or_else(|_| panic!("Sending to {:?} failed", addr));
.unwrap_or_else(|_| panic!("Sending to {addr:?} failed"));
client
.set_read_timeout(Some(Duration::from_secs(2)))
.expect("Setting read timeout failed");
@ -44,33 +41,21 @@ fn main() {
}
let req_id = RequestId::from_bytes(src_data).unwrap();
if pus_tm.subservice() == 1 {
println!(
"Received TM[1,1] acceptance success for request ID {}",
req_id
)
println!("Received TM[1,1] acceptance success for request ID {req_id}")
} else if pus_tm.subservice() == 2 {
println!(
"Received TM[1,2] acceptance failure for request ID {}",
req_id
)
println!("Received TM[1,2] acceptance failure for request ID {req_id}")
} else if pus_tm.subservice() == 3 {
println!("Received TM[1,3] start success for request ID {}", req_id)
println!("Received TM[1,3] start success for request ID {req_id}")
} else if pus_tm.subservice() == 4 {
println!("Received TM[1,2] start failure for request ID {}", req_id)
println!("Received TM[1,2] start failure for request ID {req_id}")
} else if pus_tm.subservice() == 5 {
println!("Received TM[1,5] step success for request ID {}", req_id)
println!("Received TM[1,5] step success for request ID {req_id}")
} else if pus_tm.subservice() == 6 {
println!("Received TM[1,6] step failure for request ID {}", req_id)
println!("Received TM[1,6] step failure for request ID {req_id}")
} else if pus_tm.subservice() == 7 {
println!(
"Received TM[1,7] completion success for request ID {}",
req_id
)
println!("Received TM[1,7] completion success for request ID {req_id}")
} else if pus_tm.subservice() == 8 {
println!(
"Received TM[1,8] completion failure for request ID {}",
req_id
);
println!("Received TM[1,8] completion failure for request ID {req_id}");
}
} else {
println!(

View File

@ -49,7 +49,7 @@ fn main() {
let jh0 = thread::spawn(move || {
let data = r0.recv().unwrap();
let raw = data.get_data();
println!("Received data {:?}", raw);
println!("Received data {raw:?}");
});
let jh1 = thread::spawn(|| {});
jh0.join().unwrap();

View File

@ -181,7 +181,7 @@ impl PusReceiver {
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));
.unwrap_or_else(|_| panic!("Sending HK request {request:?} failed"));
};
if PusPacket::subservice(pus_tc) == hk::Subservice::TcEnableGeneration as u8 {
send_request(HkRequest::Enable(addressable_id));

View File

@ -60,10 +60,10 @@ impl Display for MpscStoreAndSendError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
MpscStoreAndSendError::StoreError(s) => {
write!(f, "store error {}", s)
write!(f, "store error {s}")
}
MpscStoreAndSendError::SendError(s) => {
write!(f, "send error {}", s)
write!(f, "send error {s}")
}
}
}
@ -245,8 +245,8 @@ fn core_tmtc_loop(
.ok();
}
Err(e) => {
lkoester marked this conversation as resolved Outdated

can be deleted

can be deleted
println!("error creating PUS TC from raw data: {}", e);
println!("raw data: {:x?}", data);
println!("error creating PUS TC from raw data: {e}");
println!("raw data: {data:x?}");
}
}
}
@ -266,7 +266,7 @@ fn poll_tc_server(udp_tmtc_server: &mut UdpTmtcServer) -> bool {
Ok(_) => true,
Err(e) => match e {
ReceiveResult::ReceiverError(e) => match e {
CcsdsError::PacketError(e) => {
CcsdsError::ByteConversionError(e) => {
println!("Got packet error: {e:?}");
true
}
@ -295,7 +295,7 @@ fn core_tm_handling(udp_tmtc_server: &mut UdpTmtcServer, recv_addr: &SocketAddr)
if buf.len() > 9 {
let service = buf[7];
let subservice = buf[8];
println!("Sending PUS TM[{},{}]", service, subservice)
println!("Sending PUS TM[{service},{subservice}]")
} else {
println!("Sending PUS TM");
}