2023-07-05 14:25:51 +02:00
|
|
|
use crate::events::EventU32;
|
|
|
|
use crate::pus::event_man::{EventRequest, EventRequestWithToken};
|
2024-01-31 12:09:55 +01:00
|
|
|
use crate::pus::verification::TcStateToken;
|
2024-05-01 21:13:08 +02:00
|
|
|
use crate::pus::{DirectPusPacketHandlerResult, PartialPusHandlingError, PusPacketHandlingError};
|
2024-04-04 15:18:53 +02:00
|
|
|
use crate::queue::GenericSendError;
|
2023-07-05 14:25:51 +02:00
|
|
|
use spacepackets::ecss::event::Subservice;
|
|
|
|
use spacepackets::ecss::PusPacket;
|
2023-07-10 00:29:31 +02:00
|
|
|
use std::sync::mpsc::Sender;
|
2023-07-05 14:25:51 +02:00
|
|
|
|
2024-02-20 14:33:21 +01:00
|
|
|
use super::verification::VerificationReportingProvider;
|
2024-02-26 15:18:15 +01:00
|
|
|
use super::{
|
2024-04-16 11:04:22 +02:00
|
|
|
EcssTcInMemConverter, EcssTcReceiver, EcssTmSender, GenericConversionError,
|
2024-05-01 21:13:08 +02:00
|
|
|
GenericRoutingError, HandlingStatus, PusServiceHelper,
|
2024-02-26 15:18:15 +01:00
|
|
|
};
|
2024-01-31 11:40:01 +01:00
|
|
|
|
2024-04-04 15:18:53 +02:00
|
|
|
pub struct PusEventServiceHandler<
|
2024-04-16 11:04:22 +02:00
|
|
|
TcReceiver: EcssTcReceiver,
|
|
|
|
TmSender: EcssTmSender,
|
2024-02-20 14:33:21 +01:00
|
|
|
TcInMemConverter: EcssTcInMemConverter,
|
|
|
|
VerificationReporter: VerificationReportingProvider,
|
|
|
|
> {
|
2024-02-26 15:18:15 +01:00
|
|
|
pub service_helper:
|
|
|
|
PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
|
2023-07-05 14:25:51 +02:00
|
|
|
event_request_tx: Sender<EventRequestWithToken>,
|
|
|
|
}
|
|
|
|
|
2024-02-20 14:33:21 +01:00
|
|
|
impl<
|
2024-04-16 11:04:22 +02:00
|
|
|
TcReceiver: EcssTcReceiver,
|
|
|
|
TmSender: EcssTmSender,
|
2024-02-20 14:33:21 +01:00
|
|
|
TcInMemConverter: EcssTcInMemConverter,
|
|
|
|
VerificationReporter: VerificationReportingProvider,
|
2024-04-04 15:18:53 +02:00
|
|
|
> PusEventServiceHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
|
2024-02-20 14:33:21 +01:00
|
|
|
{
|
2023-07-05 14:25:51 +02:00
|
|
|
pub fn new(
|
2024-02-26 15:18:15 +01:00
|
|
|
service_helper: PusServiceHelper<
|
|
|
|
TcReceiver,
|
|
|
|
TmSender,
|
|
|
|
TcInMemConverter,
|
|
|
|
VerificationReporter,
|
|
|
|
>,
|
2023-07-05 14:25:51 +02:00
|
|
|
event_request_tx: Sender<EventRequestWithToken>,
|
|
|
|
) -> Self {
|
|
|
|
Self {
|
2024-02-26 11:41:42 +01:00
|
|
|
service_helper,
|
2023-07-05 14:25:51 +02:00
|
|
|
event_request_tx,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-01 21:13:08 +02:00
|
|
|
pub fn poll_and_handle_next_tc<ErrorCb: FnMut(&PartialPusHandlingError)>(
|
2024-04-04 15:18:53 +02:00
|
|
|
&mut self,
|
2024-05-01 21:13:08 +02:00
|
|
|
mut error_callback: ErrorCb,
|
2024-04-04 15:18:53 +02:00
|
|
|
time_stamp: &[u8],
|
2024-05-01 21:13:08 +02:00
|
|
|
) -> Result<DirectPusPacketHandlerResult, PusPacketHandlingError> {
|
2024-02-03 13:41:51 +01:00
|
|
|
let possible_packet = self.service_helper.retrieve_and_accept_next_packet()?;
|
2024-01-30 01:18:48 +01:00
|
|
|
if possible_packet.is_none() {
|
2024-05-01 21:13:08 +02:00
|
|
|
return Ok(HandlingStatus::Empty.into());
|
2024-01-30 01:18:48 +01:00
|
|
|
}
|
2024-01-31 01:32:03 +01:00
|
|
|
let ecss_tc_and_token = possible_packet.unwrap();
|
2024-04-04 15:18:53 +02:00
|
|
|
self.service_helper
|
|
|
|
.tc_in_mem_converter_mut()
|
|
|
|
.cache(&ecss_tc_and_token.tc_in_memory)?;
|
|
|
|
let tc = self.service_helper.tc_in_mem_converter().convert()?;
|
2023-07-05 21:08:04 +02:00
|
|
|
let subservice = tc.subservice();
|
|
|
|
let srv = Subservice::try_from(subservice);
|
2023-07-05 14:25:51 +02:00
|
|
|
if srv.is_err() {
|
2024-05-01 21:13:08 +02:00
|
|
|
return Ok(DirectPusPacketHandlerResult::CustomSubservice(
|
2023-07-05 14:25:51 +02:00
|
|
|
tc.subservice(),
|
2024-01-31 01:32:03 +01:00
|
|
|
ecss_tc_and_token.token,
|
2023-07-05 14:25:51 +02:00
|
|
|
));
|
|
|
|
}
|
2024-05-01 21:13:08 +02:00
|
|
|
let mut handle_enable_disable_request =
|
|
|
|
|enable: bool| -> Result<DirectPusPacketHandlerResult, PusPacketHandlingError> {
|
2024-04-04 15:18:53 +02:00
|
|
|
if tc.user_data().len() < 4 {
|
|
|
|
return Err(GenericConversionError::NotEnoughAppData {
|
|
|
|
expected: 4,
|
|
|
|
found: tc.user_data().len(),
|
|
|
|
}
|
|
|
|
.into());
|
|
|
|
}
|
|
|
|
let user_data = tc.user_data();
|
|
|
|
let event_u32 =
|
|
|
|
EventU32::from(u32::from_be_bytes(user_data[0..4].try_into().unwrap()));
|
|
|
|
let mut token: TcStateToken = ecss_tc_and_token.token.into();
|
2024-05-01 21:13:08 +02:00
|
|
|
match self.service_helper.common.verif_reporter.start_success(
|
|
|
|
&self.service_helper.common.tm_sender,
|
|
|
|
ecss_tc_and_token.token,
|
|
|
|
time_stamp,
|
|
|
|
) {
|
|
|
|
Ok(start_token) => {
|
|
|
|
token = start_token.into();
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
error_callback(&PartialPusHandlingError::Verification(e));
|
|
|
|
}
|
2023-07-05 14:25:51 +02:00
|
|
|
}
|
2024-05-01 21:13:08 +02:00
|
|
|
|
2024-04-04 15:18:53 +02:00
|
|
|
let event_req_with_token = if enable {
|
|
|
|
EventRequestWithToken {
|
|
|
|
request: EventRequest::Enable(event_u32),
|
|
|
|
token,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
EventRequestWithToken {
|
|
|
|
request: EventRequest::Disable(event_u32),
|
|
|
|
token,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
self.event_request_tx
|
|
|
|
.send(event_req_with_token)
|
|
|
|
.map_err(|_| {
|
|
|
|
PusPacketHandlingError::RequestRouting(GenericRoutingError::Send(
|
|
|
|
GenericSendError::RxDisconnected,
|
|
|
|
))
|
|
|
|
})?;
|
2024-05-01 21:13:08 +02:00
|
|
|
Ok(HandlingStatus::HandledOne.into())
|
2023-07-05 14:25:51 +02:00
|
|
|
};
|
2024-04-04 15:18:53 +02:00
|
|
|
|
2023-07-05 14:25:51 +02:00
|
|
|
match srv.unwrap() {
|
|
|
|
Subservice::TmInfoReport
|
|
|
|
| Subservice::TmLowSeverityReport
|
|
|
|
| Subservice::TmMediumSeverityReport
|
|
|
|
| Subservice::TmHighSeverityReport => {
|
2024-04-04 15:18:53 +02:00
|
|
|
return Err(PusPacketHandlingError::RequestConversion(
|
|
|
|
GenericConversionError::WrongService(tc.subservice()),
|
|
|
|
))
|
2023-07-05 14:25:51 +02:00
|
|
|
}
|
|
|
|
Subservice::TcEnableEventGeneration => {
|
2024-04-04 15:18:53 +02:00
|
|
|
handle_enable_disable_request(true)?;
|
2023-07-05 14:25:51 +02:00
|
|
|
}
|
|
|
|
Subservice::TcDisableEventGeneration => {
|
2024-04-04 15:18:53 +02:00
|
|
|
handle_enable_disable_request(false)?;
|
2023-07-05 14:25:51 +02:00
|
|
|
}
|
|
|
|
Subservice::TcReportDisabledList | Subservice::TmDisabledEventsReport => {
|
2024-05-01 21:13:08 +02:00
|
|
|
return Ok(DirectPusPacketHandlerResult::SubserviceNotImplemented(
|
2024-01-31 01:32:03 +01:00
|
|
|
subservice,
|
|
|
|
ecss_tc_and_token.token,
|
2023-07-05 14:25:51 +02:00
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-01 21:13:08 +02:00
|
|
|
Ok(HandlingStatus::HandledOne.into())
|
2023-07-05 14:25:51 +02:00
|
|
|
}
|
|
|
|
}
|
2024-02-03 13:41:51 +01:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use delegate::delegate;
|
|
|
|
use spacepackets::ecss::event::Subservice;
|
2024-04-04 15:18:53 +02:00
|
|
|
use spacepackets::time::{cds, TimeWriter};
|
2024-02-03 13:41:51 +01:00
|
|
|
use spacepackets::util::UnsignedEnum;
|
|
|
|
use spacepackets::{
|
|
|
|
ecss::{
|
|
|
|
tc::{PusTcCreator, PusTcSecondaryHeader},
|
|
|
|
tm::PusTmReader,
|
|
|
|
},
|
2024-04-04 15:18:53 +02:00
|
|
|
SpHeader,
|
2024-02-03 13:41:51 +01:00
|
|
|
};
|
|
|
|
use std::sync::mpsc::{self, Sender};
|
|
|
|
|
|
|
|
use crate::pus::event_man::EventRequest;
|
2024-04-04 15:18:53 +02:00
|
|
|
use crate::pus::test_util::{PusTestHarness, SimplePusPacketHandler, TEST_APID};
|
2024-02-26 11:41:42 +01:00
|
|
|
use crate::pus::verification::{
|
2024-04-04 15:18:53 +02:00
|
|
|
RequestId, VerificationReporter, VerificationReportingProvider,
|
2024-02-26 11:41:42 +01:00
|
|
|
};
|
2024-05-01 21:13:08 +02:00
|
|
|
use crate::pus::{GenericConversionError, HandlingStatus, MpscTcReceiver};
|
2024-04-16 11:04:22 +02:00
|
|
|
use crate::tmtc::PacketSenderWithSharedPool;
|
2024-02-03 13:41:51 +01:00
|
|
|
use crate::{
|
|
|
|
events::EventU32,
|
|
|
|
pus::{
|
|
|
|
event_man::EventRequestWithToken,
|
2024-04-04 15:18:53 +02:00
|
|
|
tests::PusServiceHandlerWithSharedStoreCommon,
|
2024-02-03 13:41:51 +01:00
|
|
|
verification::{TcStateAccepted, VerificationToken},
|
2024-05-01 21:13:08 +02:00
|
|
|
DirectPusPacketHandlerResult, EcssTcInSharedStoreConverter, PusPacketHandlingError,
|
2024-02-03 13:41:51 +01:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2024-04-04 15:18:53 +02:00
|
|
|
use super::PusEventServiceHandler;
|
2024-02-03 13:41:51 +01:00
|
|
|
|
2024-04-24 18:36:00 +02:00
|
|
|
const TEST_EVENT_0: EventU32 = EventU32::new(crate::events::Severity::Info, 5, 25);
|
2024-02-03 13:41:51 +01:00
|
|
|
|
|
|
|
struct Pus5HandlerWithStoreTester {
|
|
|
|
common: PusServiceHandlerWithSharedStoreCommon,
|
2024-04-04 15:18:53 +02:00
|
|
|
handler: PusEventServiceHandler<
|
2024-02-26 15:18:15 +01:00
|
|
|
MpscTcReceiver,
|
2024-04-16 11:04:22 +02:00
|
|
|
PacketSenderWithSharedPool,
|
2024-02-26 11:41:42 +01:00
|
|
|
EcssTcInSharedStoreConverter,
|
2024-04-04 15:18:53 +02:00
|
|
|
VerificationReporter,
|
2024-02-26 11:41:42 +01:00
|
|
|
>,
|
2024-02-03 13:41:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Pus5HandlerWithStoreTester {
|
|
|
|
pub fn new(event_request_tx: Sender<EventRequestWithToken>) -> Self {
|
2024-04-04 15:18:53 +02:00
|
|
|
let (common, srv_handler) = PusServiceHandlerWithSharedStoreCommon::new(0);
|
2024-02-03 13:41:51 +01:00
|
|
|
Self {
|
|
|
|
common,
|
2024-04-04 15:18:53 +02:00
|
|
|
handler: PusEventServiceHandler::new(srv_handler, event_request_tx),
|
2024-02-03 13:41:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PusTestHarness for Pus5HandlerWithStoreTester {
|
2024-04-04 15:18:53 +02:00
|
|
|
fn init_verification(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted> {
|
|
|
|
let init_token = self.handler.service_helper.verif_reporter_mut().add_tc(tc);
|
|
|
|
self.handler
|
|
|
|
.service_helper
|
|
|
|
.verif_reporter()
|
|
|
|
.acceptance_success(self.handler.service_helper.tm_sender(), init_token, &[0; 7])
|
|
|
|
.expect("acceptance success failure")
|
|
|
|
}
|
|
|
|
|
2024-04-16 11:04:22 +02:00
|
|
|
fn send_tc(&self, token: &VerificationToken<TcStateAccepted>, tc: &PusTcCreator) {
|
|
|
|
self.common
|
|
|
|
.send_tc(self.handler.service_helper.id(), token, tc);
|
|
|
|
}
|
|
|
|
|
2024-02-03 13:41:51 +01:00
|
|
|
delegate! {
|
|
|
|
to self.common {
|
|
|
|
fn read_next_tm(&mut self) -> PusTmReader<'_>;
|
|
|
|
fn check_no_tm_available(&self) -> bool;
|
|
|
|
fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SimplePusPacketHandler for Pus5HandlerWithStoreTester {
|
2024-05-01 21:13:08 +02:00
|
|
|
fn handle_one_tc(
|
|
|
|
&mut self,
|
|
|
|
) -> Result<DirectPusPacketHandlerResult, PusPacketHandlingError> {
|
2024-04-04 15:18:53 +02:00
|
|
|
let time_stamp = cds::CdsTime::new_with_u16_days(0, 0).to_vec().unwrap();
|
2024-05-01 21:13:08 +02:00
|
|
|
self.handler.poll_and_handle_next_tc(|_| {}, &time_stamp)
|
2024-02-03 13:41:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn event_test(
|
|
|
|
test_harness: &mut (impl PusTestHarness + SimplePusPacketHandler),
|
|
|
|
subservice: Subservice,
|
|
|
|
expected_event_req: EventRequest,
|
|
|
|
event_req_receiver: mpsc::Receiver<EventRequestWithToken>,
|
|
|
|
) {
|
2024-04-04 15:18:53 +02:00
|
|
|
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, 0, 0);
|
2024-02-03 13:41:51 +01:00
|
|
|
let sec_header = PusTcSecondaryHeader::new_simple(5, subservice as u8);
|
|
|
|
let mut app_data = [0; 4];
|
|
|
|
TEST_EVENT_0
|
|
|
|
.write_to_be_bytes(&mut app_data)
|
|
|
|
.expect("writing test event failed");
|
2024-04-04 15:18:53 +02:00
|
|
|
let ping_tc = PusTcCreator::new(sp_header, sec_header, &app_data, true);
|
|
|
|
let token = test_harness.init_verification(&ping_tc);
|
|
|
|
test_harness.send_tc(&token, &ping_tc);
|
|
|
|
let request_id = token.request_id();
|
2024-02-03 13:41:51 +01:00
|
|
|
test_harness.handle_one_tc().unwrap();
|
|
|
|
test_harness.check_next_verification_tm(1, request_id);
|
|
|
|
test_harness.check_next_verification_tm(3, request_id);
|
|
|
|
// Completion TM is not generated for us.
|
|
|
|
assert!(test_harness.check_no_tm_available());
|
|
|
|
let event_request = event_req_receiver
|
|
|
|
.try_recv()
|
|
|
|
.expect("no event request received");
|
|
|
|
assert_eq!(expected_event_req, event_request.request);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_enabling_event_reporting() {
|
|
|
|
let (event_request_tx, event_request_rx) = mpsc::channel();
|
|
|
|
let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
|
|
|
|
event_test(
|
|
|
|
&mut test_harness,
|
|
|
|
Subservice::TcEnableEventGeneration,
|
|
|
|
EventRequest::Enable(TEST_EVENT_0),
|
|
|
|
event_request_rx,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_disabling_event_reporting() {
|
|
|
|
let (event_request_tx, event_request_rx) = mpsc::channel();
|
|
|
|
let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
|
|
|
|
event_test(
|
|
|
|
&mut test_harness,
|
|
|
|
Subservice::TcDisableEventGeneration,
|
|
|
|
EventRequest::Disable(TEST_EVENT_0),
|
|
|
|
event_request_rx,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_empty_tc_queue() {
|
|
|
|
let (event_request_tx, _) = mpsc::channel();
|
|
|
|
let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
|
|
|
|
let result = test_harness.handle_one_tc();
|
|
|
|
assert!(result.is_ok());
|
|
|
|
let result = result.unwrap();
|
2024-05-01 21:13:08 +02:00
|
|
|
assert!(
|
|
|
|
matches!(
|
|
|
|
result,
|
|
|
|
DirectPusPacketHandlerResult::Handled(HandlingStatus::Empty)
|
|
|
|
),
|
|
|
|
"unexpected result type {result:?}"
|
|
|
|
)
|
2024-02-03 13:41:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_sending_custom_subservice() {
|
|
|
|
let (event_request_tx, _) = mpsc::channel();
|
|
|
|
let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
|
2024-04-04 15:18:53 +02:00
|
|
|
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, 0, 0);
|
2024-02-03 13:41:51 +01:00
|
|
|
let sec_header = PusTcSecondaryHeader::new_simple(5, 200);
|
2024-04-04 15:18:53 +02:00
|
|
|
let ping_tc = PusTcCreator::new_no_app_data(sp_header, sec_header, true);
|
|
|
|
let token = test_harness.init_verification(&ping_tc);
|
|
|
|
test_harness.send_tc(&token, &ping_tc);
|
2024-02-03 13:41:51 +01:00
|
|
|
let result = test_harness.handle_one_tc();
|
|
|
|
assert!(result.is_ok());
|
|
|
|
let result = result.unwrap();
|
2024-05-01 21:13:08 +02:00
|
|
|
if let DirectPusPacketHandlerResult::CustomSubservice(subservice, _) = result {
|
2024-02-03 13:41:51 +01:00
|
|
|
assert_eq!(subservice, 200);
|
|
|
|
} else {
|
|
|
|
panic!("unexpected result type {result:?}")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_sending_invalid_app_data() {
|
|
|
|
let (event_request_tx, _) = mpsc::channel();
|
|
|
|
let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
|
2024-04-04 15:18:53 +02:00
|
|
|
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, 0, 0);
|
2024-02-03 13:41:51 +01:00
|
|
|
let sec_header =
|
|
|
|
PusTcSecondaryHeader::new_simple(5, Subservice::TcEnableEventGeneration as u8);
|
2024-04-04 15:18:53 +02:00
|
|
|
let ping_tc = PusTcCreator::new(sp_header, sec_header, &[0, 1, 2], true);
|
|
|
|
let token = test_harness.init_verification(&ping_tc);
|
|
|
|
test_harness.send_tc(&token, &ping_tc);
|
2024-02-03 13:41:51 +01:00
|
|
|
let result = test_harness.handle_one_tc();
|
|
|
|
assert!(result.is_err());
|
|
|
|
let result = result.unwrap_err();
|
2024-04-04 15:18:53 +02:00
|
|
|
if let PusPacketHandlingError::RequestConversion(
|
|
|
|
GenericConversionError::NotEnoughAppData { expected, found },
|
|
|
|
) = result
|
|
|
|
{
|
2024-02-20 14:33:21 +01:00
|
|
|
assert_eq!(expected, 4);
|
|
|
|
assert_eq!(found, 3);
|
2024-02-03 13:41:51 +01:00
|
|
|
} else {
|
|
|
|
panic!("unexpected result type {result:?}")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|