use crate::thread::KernelPID;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use riot_sys::libc;
use riot_sys::{self, kernel_pid_t, msg_receive, msg_reply, msg_send, msg_send_receive, msg_t};
#[cfg(feature = "with_msg_v2")]
pub mod v2;
#[derive(Debug, PartialEq)]
pub enum MsgSender {
Invalid, Thread(KernelPID),
ISR, }
impl MsgSender {
fn from_pid(pid: kernel_pid_t) -> Self {
if pid == crate::thread::KERNEL_PID_ISR {
MsgSender::ISR
} else {
KernelPID::new(pid)
.map(MsgSender::Thread)
.unwrap_or(MsgSender::Invalid)
}
}
}
#[derive(Debug)]
pub enum MsgSendError {
ReceiverNotWaiting,
InvalidPID,
}
pub trait Msg {
fn get_sender(&self) -> MsgSender;
fn get_type(&self) -> u16;
fn send(self, target: &KernelPID) -> Result<(), MsgSendError>;
fn send_receive(self, target: &KernelPID) -> OpaqueMsg;
fn reply(self, response: impl WrapsMsgT) -> Result<(), ()>;
}
pub trait WrapsMsgT {
fn extract(self) -> msg_t;
fn view(&self) -> &msg_t;
}
impl<T> Msg for T
where
T: WrapsMsgT,
{
fn send(self, target: &KernelPID) -> Result<(), MsgSendError> {
let mut m = self.extract();
match unsafe { msg_send(&mut m, target.into()) } {
1 => Ok(()),
0 => Err(MsgSendError::ReceiverNotWaiting),
_ => Err(MsgSendError::InvalidPID),
}
}
fn send_receive(self, target: &KernelPID) -> OpaqueMsg {
let mut m = self.extract();
let _ = unsafe { msg_send_receive(&mut m, &mut m, target.into()) };
OpaqueMsg(m)
}
fn reply(self, response: impl WrapsMsgT) -> Result<(), ()> {
let mut m = self.extract();
let mut r = response.extract();
let result = unsafe { msg_reply(&mut m, &mut r) };
match result {
1 => Ok(()),
_ => Err(()),
}
}
fn get_sender(&self) -> MsgSender {
MsgSender::from_pid(self.view().sender_pid)
}
fn get_type(&self) -> u16 {
self.view().type_
}
}
pub struct OpaqueMsg(msg_t);
impl OpaqueMsg {
pub fn receive() -> OpaqueMsg {
let mut m: MaybeUninit<msg_t> = MaybeUninit::uninit();
let _ = unsafe { msg_receive(m.as_mut_ptr()) };
OpaqueMsg(unsafe { m.assume_init() })
}
}
impl ::core::fmt::Debug for OpaqueMsg {
fn fmt(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
formatter
.debug_struct("OpaqueMsg")
.field("from", &self.get_sender())
.field("type", &self.get_type())
.finish()
}
}
impl WrapsMsgT for OpaqueMsg {
fn extract(self) -> msg_t {
self.0
}
fn view(&self) -> &msg_t {
&self.0
}
}
pub struct EmptyMsg(msg_t);
impl EmptyMsg {
pub fn new(type_: u16) -> Self {
EmptyMsg(msg_t {
type_,
..msg_t::default()
})
}
}
impl WrapsMsgT for EmptyMsg {
fn extract(self) -> msg_t {
self.0
}
fn view(&self) -> &msg_t {
&self.0
}
}
#[derive(Debug)]
pub struct NumericMsg(msg_t);
impl NumericMsg {
pub fn new(type_: u16, value: u32) -> Self {
NumericMsg(msg_t {
type_,
content: riot_sys::msg_t__bindgen_ty_1 { value: value },
..msg_t::default()
})
}
pub unsafe fn recognize(msg: OpaqueMsg) -> Self {
NumericMsg(msg.extract())
}
pub fn get_value(&self) -> u32 {
unsafe { self.0.content.value }
}
}
impl WrapsMsgT for NumericMsg {
fn extract(self) -> msg_t {
self.0
}
fn view(&self) -> &msg_t {
&self.0
}
}
pub struct ContainerMsg<T> {
message: msg_t,
t: PhantomData<T>,
}
impl<T> ContainerMsg<T>
where
T: Sized + Send,
{
pub fn new(type_: u16, value: T) -> Self {
use core::mem::size_of;
const {
assert!(
size_of::<T>() <= size_of::<*mut libc::c_void>(),
"Type too large to send"
)
};
ContainerMsg {
message: msg_t {
type_,
content: riot_sys::msg_t__bindgen_ty_1 {
ptr: unsafe { ::core::mem::transmute_copy(&value) },
},
..msg_t::default()
},
t: PhantomData,
}
}
pub fn get_value(self) -> T {
unsafe { ::core::mem::transmute_copy(&self.message.content.ptr) }
}
pub unsafe fn recognize(msg: OpaqueMsg) -> Self {
ContainerMsg {
message: msg.extract(),
t: PhantomData,
}
}
}