use core::mem::size_of; use satrs_shared::res_code::ResultU16; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use spacepackets::ByteConversionError; #[cfg(feature = "alloc")] pub use alloc_mod::*; #[cfg(feature = "std")] pub use std_mod::*; use crate::{ queue::{GenericReceiveError, GenericSendError}, request::{ GenericMessage, MessageMetadata, MessageReceiverProvider, MessageReceiverWithId, RequestId, }, ComponentId, }; pub type Mode = u32; pub type Submode = u16; #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ModeAndSubmode { mode: Mode, submode: Submode, } pub const INVALID_MODE_VAL: Mode = Mode::MAX; pub const UNKNOWN_MODE_VAL: Mode = Mode::MAX - 1; pub const INVALID_MODE: ModeAndSubmode = ModeAndSubmode::new(INVALID_MODE_VAL, 0); pub const UNKNOWN_MODE: ModeAndSubmode = ModeAndSubmode::new(UNKNOWN_MODE_VAL, 0); impl ModeAndSubmode { pub const RAW_LEN: usize = size_of::() + size_of::(); pub const fn new_mode_only(mode: Mode) -> Self { Self { mode, submode: 0 } } pub const fn new(mode: Mode, submode: Submode) -> Self { Self { mode, submode } } pub fn from_be_bytes(buf: &[u8]) -> Result { if buf.len() < 6 { return Err(ByteConversionError::FromSliceTooSmall { expected: Self::RAW_LEN, found: buf.len(), }); } Ok(Self { mode: Mode::from_be_bytes(buf[0..size_of::()].try_into().unwrap()), submode: Submode::from_be_bytes( buf[size_of::()..size_of::() + size_of::()] .try_into() .unwrap(), ), }) } pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { if buf.len() < Self::RAW_LEN { return Err(ByteConversionError::ToSliceTooSmall { expected: Self::RAW_LEN, found: buf.len(), }); } buf[0..size_of::()].copy_from_slice(&self.mode.to_be_bytes()); buf[size_of::()..Self::RAW_LEN].copy_from_slice(&self.submode.to_be_bytes()); Ok(Self::RAW_LEN) } pub fn mode(&self) -> Mode { self.mode } pub fn submode(&self) -> Submode { self.submode } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TargetedModeCommand { pub address: ComponentId, pub mode_submode: ModeAndSubmode, } impl TargetedModeCommand { pub const fn new(address: ComponentId, mode_submode: ModeAndSubmode) -> Self { Self { address, mode_submode, } } pub fn address(&self) -> ComponentId { self.address } pub fn mode_submode(&self) -> ModeAndSubmode { self.mode_submode } pub fn mode(&self) -> u32 { self.mode_submode.mode } pub fn submode(&self) -> u16 { self.mode_submode.submode } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ModeRequest { /// Mode information. Can be used to notify other components of changed modes. ModeInfo(ModeAndSubmode), SetMode { mode_and_submode: ModeAndSubmode, forced: bool, }, ReadMode, AnnounceMode, AnnounceModeRecursive, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TargetedModeRequest { target_id: ComponentId, mode_request: ModeRequest, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ModeReply { /// Mode information. Can be used to notify other components of changed modes. ModeInfo(ModeAndSubmode), /// Reply to a mode request to confirm the commanded mode was reached. ModeReply(ModeAndSubmode), // Can not reach the commanded mode. Contains a reason as a [ResultU16]. CantReachMode(ResultU16), /// We are in the wrong mode for unknown reasons. Contains the expected and reached mode. WrongMode { expected: ModeAndSubmode, reached: ModeAndSubmode, }, } pub type GenericModeReply = GenericMessage; pub trait ModeRequestSender { fn local_channel_id(&self) -> ComponentId; fn send_mode_request( &self, request_id: RequestId, target_id: ComponentId, request: ModeRequest, ) -> Result<(), GenericSendError>; } pub trait ModeRequestReceiver { fn try_recv_mode_request( &self, ) -> Result>, GenericReceiveError>; } impl> ModeRequestReceiver for MessageReceiverWithId { fn try_recv_mode_request( &self, ) -> Result>, GenericReceiveError> { self.try_recv_message() } } #[derive(Debug, Clone, thiserror::Error)] pub enum ModeError { #[error("Messaging send error: {0}")] Send(#[from] GenericSendError), #[error("Messaging receive error: {0}")] Receive(#[from] GenericReceiveError), #[error("busy with other mode request")] Busy, } pub trait ModeProvider { fn mode_and_submode(&self) -> ModeAndSubmode; fn mode(&self) -> Mode { self.mode_and_submode().mode() } fn submode(&self) -> Submode { self.mode_and_submode().submode() } } pub trait ModeRequestHandler: ModeProvider { type Error; fn start_transition( &mut self, requestor: MessageMetadata, mode_and_submode: ModeAndSubmode, forced: bool, ) -> Result<(), Self::Error>; fn announce_mode(&self, requestor_info: Option, recursive: bool); fn handle_mode_reached( &mut self, requestor_info: Option, ) -> Result<(), Self::Error>; fn handle_mode_info( &mut self, requestor_info: MessageMetadata, info: ModeAndSubmode, ) -> Result<(), Self::Error>; fn send_mode_reply( &self, requestor_info: MessageMetadata, reply: ModeReply, ) -> Result<(), Self::Error>; fn handle_mode_request( &mut self, request: GenericMessage, ) -> Result<(), Self::Error> { match request.message { ModeRequest::SetMode { mode_and_submode, forced, } => self.start_transition(request.requestor_info, mode_and_submode, forced), ModeRequest::ReadMode => self.send_mode_reply( request.requestor_info, ModeReply::ModeReply(self.mode_and_submode()), ), ModeRequest::AnnounceMode => { self.announce_mode(Some(request.requestor_info), false); Ok(()) } ModeRequest::AnnounceModeRecursive => { self.announce_mode(Some(request.requestor_info), true); Ok(()) } ModeRequest::ModeInfo(info) => self.handle_mode_info(request.requestor_info, info), } } } pub trait ModeReplyReceiver { fn try_recv_mode_reply(&self) -> Result>, GenericReceiveError>; } impl> ModeReplyReceiver for MessageReceiverWithId { fn try_recv_mode_reply( &self, ) -> Result>, GenericReceiveError> { self.try_recv_message() } } pub trait ModeReplySender { fn local_channel_id(&self) -> ComponentId; /// The requestor is assumed to be the target of the reply. fn send_mode_reply( &self, requestor_info: MessageMetadata, reply: ModeReply, ) -> Result<(), GenericSendError>; } #[cfg(feature = "alloc")] pub mod alloc_mod { use crate::{ queue::{GenericReceiveError, GenericSendError}, request::{ MessageSenderAndReceiver, MessageSenderMap, MessageSenderProvider, MessageSenderStoreProvider, RequestAndReplySenderAndReceiver, }, }; use super::*; impl> MessageSenderMap { pub fn send_mode_reply( &self, requestor_info: MessageMetadata, target_id: ComponentId, request: ModeReply, ) -> Result<(), GenericSendError> { self.send_message(requestor_info, target_id, request) } pub fn add_reply_target(&mut self, target_id: ComponentId, request_sender: S) { self.add_message_target(target_id, request_sender) } } impl< From, Sender: MessageSenderProvider, Receiver: MessageReceiverProvider, SenderStore: MessageSenderStoreProvider, > ModeReplySender for MessageSenderAndReceiver { fn local_channel_id(&self) -> ComponentId { self.local_channel_id_generic() } fn send_mode_reply( &self, requestor_info: MessageMetadata, request: ModeReply, ) -> Result<(), GenericSendError> { self.message_sender_store.send_message( MessageMetadata::new(requestor_info.request_id(), self.local_channel_id()), requestor_info.sender_id(), request, ) } } impl< To, Sender: MessageSenderProvider, Receiver: MessageReceiverProvider, SenderStore: MessageSenderStoreProvider, > ModeReplyReceiver for MessageSenderAndReceiver { fn try_recv_mode_reply( &self, ) -> Result>, GenericReceiveError> { self.message_receiver.try_recv_message() } } impl< Request, ReqSender: MessageSenderProvider, ReqReceiver: MessageReceiverProvider, ReqSenderStore: MessageSenderStoreProvider, Reply, ReplySender: MessageSenderProvider, ReplyReceiver: MessageReceiverProvider, ReplySenderStore: MessageSenderStoreProvider, > RequestAndReplySenderAndReceiver< Request, ReqSender, ReqReceiver, ReqSenderStore, Reply, ReplySender, ReplyReceiver, ReplySenderStore, > { pub fn add_reply_target(&mut self, target_id: ComponentId, reply_sender: ReplySender) { self.reply_sender_store .add_message_target(target_id, reply_sender) } } impl< Request, ReqSender: MessageSenderProvider, ReqReceiver: MessageReceiverProvider, ReqSenderStore: MessageSenderStoreProvider, ReplySender: MessageSenderProvider, ReplyReceiver: MessageReceiverProvider, ReplySenderStore: MessageSenderStoreProvider, > ModeReplySender for RequestAndReplySenderAndReceiver< Request, ReqSender, ReqReceiver, ReqSenderStore, ModeReply, ReplySender, ReplyReceiver, ReplySenderStore, > { fn local_channel_id(&self) -> ComponentId { self.local_channel_id_generic() } fn send_mode_reply( &self, requestor_info: MessageMetadata, reply: ModeReply, ) -> Result<(), GenericSendError> { self.reply_sender_store.send_message( MessageMetadata::new(requestor_info.request_id(), self.local_channel_id()), requestor_info.sender_id(), reply, ) } } impl< Request, ReqSender: MessageSenderProvider, ReqReceiver: MessageReceiverProvider, ReqSenderStore: MessageSenderStoreProvider, ReplySender: MessageSenderProvider, ReplyReceiver: MessageReceiverProvider, ReplySenderStore: MessageSenderStoreProvider, > ModeReplyReceiver for RequestAndReplySenderAndReceiver< Request, ReqSender, ReqReceiver, ReqSenderStore, ModeReply, ReplySender, ReplyReceiver, ReplySenderStore, > { fn try_recv_mode_reply( &self, ) -> Result>, GenericReceiveError> { self.reply_receiver.try_recv_message() } } /// Helper type definition for a mode handler which can handle mode requests. pub type ModeRequestHandlerInterface = MessageSenderAndReceiver; impl< Sender: MessageSenderProvider, Receiver: MessageReceiverProvider, ReplySenderStore: MessageSenderStoreProvider, > ModeRequestHandlerInterface { pub fn try_recv_mode_request( &self, ) -> Result>, GenericReceiveError> { self.try_recv_message() } pub fn send_mode_reply( &self, requestor_info: MessageMetadata, reply: ModeReply, ) -> Result<(), GenericSendError> { self.send_message( requestor_info.request_id(), requestor_info.sender_id(), reply, ) } } /// Helper type defintion for a mode handler object which can send mode requests and receive /// mode replies. pub type ModeRequestorInterface = MessageSenderAndReceiver; impl< Sender: MessageSenderProvider, Receiver: MessageReceiverProvider, RequestSenderStore: MessageSenderStoreProvider, > ModeRequestorInterface { pub fn try_recv_mode_reply( &self, ) -> Result>, GenericReceiveError> { self.try_recv_message() } pub fn send_mode_request( &self, request_id: RequestId, target_id: ComponentId, reply: ModeRequest, ) -> Result<(), GenericSendError> { self.send_message(request_id, target_id, reply) } } /// Helper type defintion for a mode handler object which can both send mode requests and /// process mode requests. pub type ModeInterface< ReqSender, ReqReceiver, ReqSenderStore, ReplySender, ReplyReceiver, ReplySenderStore, > = RequestAndReplySenderAndReceiver< ModeRequest, ReqSender, ReqReceiver, ReqSenderStore, ModeReply, ReplySender, ReplyReceiver, ReplySenderStore, >; impl> MessageSenderMap { pub fn send_mode_request( &self, requestor_info: MessageMetadata, target_id: ComponentId, request: ModeRequest, ) -> Result<(), GenericSendError> { self.send_message(requestor_info, target_id, request) } pub fn add_request_target(&mut self, target_id: ComponentId, request_sender: S) { self.add_message_target(target_id, request_sender) } } impl< To, Sender: MessageSenderProvider, Receiver: MessageReceiverProvider, SenderStore: MessageSenderStoreProvider, > ModeRequestReceiver for MessageSenderAndReceiver { fn try_recv_mode_request( &self, ) -> Result>, GenericReceiveError> { self.message_receiver.try_recv_message() } } impl< From, Sender: MessageSenderProvider, Receiver: MessageReceiverProvider, SenderStore: MessageSenderStoreProvider, > ModeRequestSender for MessageSenderAndReceiver { fn local_channel_id(&self) -> ComponentId { self.local_channel_id_generic() } fn send_mode_request( &self, request_id: RequestId, target_id: ComponentId, request: ModeRequest, ) -> Result<(), GenericSendError> { self.message_sender_store.send_message( MessageMetadata::new(request_id, self.local_channel_id()), target_id, request, ) } } impl< ReqSender: MessageSenderProvider, ReqReceiver: MessageReceiverProvider, ReqSenderStore: MessageSenderStoreProvider, Reply, ReplySender: MessageSenderProvider, ReplyReceiver: MessageReceiverProvider, ReplySenderStore: MessageSenderStoreProvider, > RequestAndReplySenderAndReceiver< ModeRequest, ReqSender, ReqReceiver, ReqSenderStore, Reply, ReplySender, ReplyReceiver, ReplySenderStore, > { pub fn add_request_target(&mut self, target_id: ComponentId, request_sender: ReqSender) { self.request_sender_store .add_message_target(target_id, request_sender) } } impl< ReqSender: MessageSenderProvider, ReqReceiver: MessageReceiverProvider, ReqSenderStore: MessageSenderStoreProvider, Reply, ReplySender: MessageSenderProvider, ReplyReceiver: MessageReceiverProvider, ReplySenderStore: MessageSenderStoreProvider, > ModeRequestSender for RequestAndReplySenderAndReceiver< ModeRequest, ReqSender, ReqReceiver, ReqSenderStore, Reply, ReplySender, ReplyReceiver, ReplySenderStore, > { fn local_channel_id(&self) -> ComponentId { self.local_channel_id_generic() } fn send_mode_request( &self, request_id: RequestId, target_id: ComponentId, request: ModeRequest, ) -> Result<(), GenericSendError> { self.request_sender_store.send_message( MessageMetadata::new(request_id, self.local_channel_id()), target_id, request, ) } } impl< ReqSender: MessageSenderProvider, ReqReceiver: MessageReceiverProvider, ReqSenderStore: MessageSenderStoreProvider, Reply, ReplySender: MessageSenderProvider, ReplyReceiver: MessageReceiverProvider, ReplySenderStore: MessageSenderStoreProvider, > ModeRequestReceiver for RequestAndReplySenderAndReceiver< ModeRequest, ReqSender, ReqReceiver, ReqSenderStore, Reply, ReplySender, ReplyReceiver, ReplySenderStore, > { fn try_recv_mode_request( &self, ) -> Result>, GenericReceiveError> { self.request_receiver.try_recv_message() } } } #[cfg(feature = "std")] pub mod std_mod { use std::sync::mpsc; use crate::request::{MessageSenderList, OneMessageSender}; use super::*; pub type ModeRequestHandlerMpsc = ModeRequestHandlerInterface< mpsc::Sender>, mpsc::Receiver>, MessageSenderList>>, >; pub type ModeRequestHandlerMpscBounded = ModeRequestHandlerInterface< mpsc::SyncSender>, mpsc::Receiver>, MessageSenderList>>, >; pub type ModeRequestorOneChildMpsc = ModeRequestorInterface< mpsc::Sender>, mpsc::Receiver>, OneMessageSender>>, >; pub type ModeRequestorOneChildBoundedMpsc = ModeRequestorInterface< mpsc::SyncSender>, mpsc::Receiver>, OneMessageSender>>, >; pub type ModeRequestorChildListMpsc = ModeRequestorInterface< mpsc::Sender>, mpsc::Receiver>, MessageSenderList>>, >; pub type ModeRequestorChildListBoundedMpsc = ModeRequestorInterface< mpsc::SyncSender>, mpsc::Receiver>, MessageSenderList>>, >; pub type ModeRequestorAndHandlerMpsc = ModeInterface< mpsc::Sender>, mpsc::Receiver>, MessageSenderList>>, mpsc::Sender>, mpsc::Receiver>, MessageSenderList>>, >; pub type ModeRequestorAndHandlerMpscBounded = ModeInterface< mpsc::SyncSender>, mpsc::Receiver>, MessageSenderList>>, mpsc::SyncSender>, mpsc::Receiver>, MessageSenderList>>, >; } #[cfg(test)] pub(crate) mod tests { use core::cell::RefCell; use std::collections::VecDeque; use crate::{request::RequestId, ComponentId}; use super::*; pub struct ModeReqWrapper { pub request_id: RequestId, pub target_id: ComponentId, pub request: ModeRequest, } #[derive(Default)] pub struct ModeReqSenderMock { pub requests: RefCell>, } impl ModeRequestSender for ModeReqSenderMock { fn local_channel_id(&self) -> crate::ComponentId { 0 } fn send_mode_request( &self, request_id: RequestId, target_id: ComponentId, request: ModeRequest, ) -> Result<(), GenericSendError> { self.requests.borrow_mut().push_back(ModeReqWrapper { request_id, target_id, request, }); Ok(()) } } }