use core::mem::size_of; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use spacepackets::ByteConversionError; use crate::{ queue::GenericTargetedMessagingError, request::{GenericMessage, MessageReceiver, MessageReceiverWithId, RequestId}, ChannelId, TargetId, }; 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, } impl ModeAndSubmode { 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 raw_len() -> usize { size_of::() + size_of::() } pub fn from_be_bytes(buf: &[u8]) -> Result { if buf.len() < 6 { return Err(ByteConversionError::FromSliceTooSmall { expected: 6, 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 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: TargetId, pub mode_submode: ModeAndSubmode, } impl TargetedModeCommand { pub const fn new(address: TargetId, mode_submode: ModeAndSubmode) -> Self { Self { address, mode_submode, } } pub fn address(&self) -> TargetId { 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 { SetMode(ModeAndSubmode), ReadMode, AnnounceMode, AnnounceModeRecursive, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ModeReply { /// Unrequest 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), CantReachMode(ModeAndSubmode), WrongMode { expected: ModeAndSubmode, reached: ModeAndSubmode, }, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TargetedModeRequest { target_id: TargetId, mode_request: ModeRequest, } pub trait ModeRequestSender { fn local_channel_id(&self) -> ChannelId; fn send_mode_request( &self, request_id: RequestId, target_id: ChannelId, request: ModeRequest, ) -> Result<(), GenericTargetedMessagingError>; } pub trait ModeReplySender { fn local_channel_id(&self) -> ChannelId; fn send_mode_reply( &self, request_id: RequestId, target_id: ChannelId, reply: ModeReply, ) -> Result<(), GenericTargetedMessagingError>; } pub trait ModeRequestReceiver { fn try_recv_mode_request( &self, ) -> Result>, GenericTargetedMessagingError>; } pub trait ModeReplyReceiver { fn try_recv_mode_reply( &self, ) -> Result>, GenericTargetedMessagingError>; } impl> ModeReplyReceiver for MessageReceiverWithId { fn try_recv_mode_reply( &self, ) -> Result>, GenericTargetedMessagingError> { self.try_recv_message() } } impl> ModeRequestReceiver for MessageReceiverWithId { fn try_recv_mode_request( &self, ) -> Result>, GenericTargetedMessagingError> { self.try_recv_message() } } pub trait ModeProvider { fn mode_and_submode(&self) -> ModeAndSubmode; } #[derive(Debug, Clone)] pub enum ModeError { Messaging(GenericTargetedMessagingError), } impl From for ModeError { fn from(value: GenericTargetedMessagingError) -> Self { Self::Messaging(value) } } pub trait ModeRequestHandler: ModeProvider { fn start_transition( &mut self, request_id: RequestId, sender_id: ChannelId, mode_and_submode: ModeAndSubmode, ) -> Result<(), ModeError>; fn announce_mode(&self, request_id: RequestId, sender_id: ChannelId, recursive: bool); fn handle_mode_reached(&mut self) -> Result<(), GenericTargetedMessagingError>; } #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] pub mod alloc_mod { use crate::request::{MessageSenderAndReceiver, RequestAndReplySenderAndReceiver}; use super::*; impl, R: MessageReceiver> ModeRequestSender for MessageSenderAndReceiver { fn local_channel_id(&self) -> ChannelId { self.local_channel_id_generic() } fn send_mode_request( &self, request_id: RequestId, target_id: ChannelId, request: ModeRequest, ) -> Result<(), GenericTargetedMessagingError> { self.message_sender_map.send_mode_request( request_id, self.local_channel_id(), target_id, request, ) } } impl< REPLY, S0: MessageSender, R0: MessageReceiver, S1: MessageSender, R1: MessageReceiver, > RequestAndReplySenderAndReceiver { pub fn add_request_target(&mut self, target_id: ChannelId, request_sender: S0) { self.request_sender_map .add_message_target(target_id, request_sender) } } impl< REQUEST, S0: MessageSender, R0: MessageReceiver, S1: MessageSender, R1: MessageReceiver, > RequestAndReplySenderAndReceiver { pub fn add_reply_target(&mut self, target_id: ChannelId, reply_sender: S1) { self.reply_sender_map .add_message_target(target_id, reply_sender) } } impl< REPLY, S0: MessageSender, R0: MessageReceiver, S1: MessageSender, R1: MessageReceiver, > ModeRequestSender for RequestAndReplySenderAndReceiver { fn local_channel_id(&self) -> ChannelId { self.local_channel_id_generic() } fn send_mode_request( &self, request_id: RequestId, target_id: ChannelId, request: ModeRequest, ) -> Result<(), GenericTargetedMessagingError> { self.request_sender_map.send_mode_request( request_id, self.local_channel_id(), target_id, request, ) } } impl< REQUEST, S0: MessageSender, R0: MessageReceiver, S1: MessageSender, R1: MessageReceiver, > ModeReplySender for RequestAndReplySenderAndReceiver { fn local_channel_id(&self) -> ChannelId { self.local_channel_id_generic() } fn send_mode_reply( &self, request_id: RequestId, target_id: ChannelId, request: ModeReply, ) -> Result<(), GenericTargetedMessagingError> { self.reply_sender_map.send_mode_reply( request_id, self.local_channel_id(), target_id, request, ) } } impl< REQUEST, S0: MessageSender, R0: MessageReceiver, S1: MessageSender, R1: MessageReceiver, > ModeReplyReceiver for RequestAndReplySenderAndReceiver { fn try_recv_mode_reply( &self, ) -> Result>, GenericTargetedMessagingError> { self.reply_receiver .try_recv_message(self.local_channel_id_generic()) } } impl< REPLY, S0: MessageSender, R0: MessageReceiver, S1: MessageSender, R1: MessageReceiver, > ModeRequestReceiver for RequestAndReplySenderAndReceiver { fn try_recv_mode_request( &self, ) -> Result>, GenericTargetedMessagingError> { self.request_receiver .try_recv_message(self.local_channel_id_generic()) } } } #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] pub mod std_mod { use std::sync::mpsc; use crate::request::{ MessageSenderAndReceiver, MessageSenderMap, MessageSenderMapWithId, RequestAndReplySenderAndReceiver, }; use super::*; impl> MessageSenderMap { pub fn send_mode_request( &self, request_id: RequestId, local_id: ChannelId, target_id: ChannelId, request: ModeRequest, ) -> Result<(), GenericTargetedMessagingError> { self.send_message(request_id, local_id, target_id, request) } pub fn add_request_target(&mut self, target_id: ChannelId, request_sender: S) { self.add_message_target(target_id, request_sender) } } impl> MessageSenderMap { pub fn send_mode_reply( &self, request_id: RequestId, local_id: ChannelId, target_id: ChannelId, request: ModeReply, ) -> Result<(), GenericTargetedMessagingError> { self.send_message(request_id, local_id, target_id, request) } pub fn add_reply_target(&mut self, target_id: ChannelId, request_sender: S) { self.add_message_target(target_id, request_sender) } } impl> ModeReplySender for MessageSenderMapWithId { fn send_mode_reply( &self, request_id: RequestId, target_channel_id: ChannelId, reply: ModeReply, ) -> Result<(), GenericTargetedMessagingError> { self.send_message(request_id, target_channel_id, reply) } fn local_channel_id(&self) -> ChannelId { self.local_channel_id } } impl> ModeRequestSender for MessageSenderMapWithId { fn local_channel_id(&self) -> ChannelId { self.local_channel_id } fn send_mode_request( &self, request_id: RequestId, target_id: ChannelId, request: ModeRequest, ) -> Result<(), GenericTargetedMessagingError> { self.send_message(request_id, target_id, request) } } impl, R: MessageReceiver> ModeReplySender for MessageSenderAndReceiver { fn local_channel_id(&self) -> ChannelId { self.local_channel_id_generic() } fn send_mode_reply( &self, request_id: RequestId, target_id: ChannelId, request: ModeReply, ) -> Result<(), GenericTargetedMessagingError> { self.message_sender_map.send_mode_reply( request_id, self.local_channel_id(), target_id, request, ) } } impl, R: MessageReceiver> ModeReplyReceiver for MessageSenderAndReceiver { fn try_recv_mode_reply( &self, ) -> Result>, GenericTargetedMessagingError> { self.message_receiver .try_recv_message(self.local_channel_id_generic()) } } impl, R: MessageReceiver> ModeRequestReceiver for MessageSenderAndReceiver { fn try_recv_mode_request( &self, ) -> Result>, GenericTargetedMessagingError> { self.message_receiver .try_recv_message(self.local_channel_id_generic()) } } pub type ModeRequestHandlerConnector = MessageSenderAndReceiver; pub type MpscModeRequestHandlerConnector = ModeRequestHandlerConnector< mpsc::Sender>, mpsc::Receiver>, >; pub type MpscBoundedModeRequestHandlerConnector = ModeRequestHandlerConnector< mpsc::SyncSender>, mpsc::Receiver>, >; pub type ModeRequestorConnector = MessageSenderAndReceiver; pub type MpscModeRequestorConnector = ModeRequestorConnector< mpsc::Sender>, mpsc::Receiver>, >; pub type MpscBoundedModeRequestorConnector = ModeRequestorConnector< mpsc::SyncSender>, mpsc::Receiver>, >; pub type ModeConnector = RequestAndReplySenderAndReceiver; pub type MpscModeConnector = ModeConnector< mpsc::Sender>, mpsc::Receiver>, mpsc::Sender>, mpsc::Receiver>, >; pub type MpscBoundedModeConnector = ModeConnector< mpsc::SyncSender>, mpsc::Receiver>, mpsc::SyncSender>, mpsc::Receiver>, >; } #[cfg(test)] mod tests {}