2023-06-19 01:51:14 +02:00
|
|
|
use core::future::poll_fn;
|
|
|
|
use core::marker::PhantomData;
|
|
|
|
use core::ptr;
|
|
|
|
use core::sync::atomic::{AtomicBool, Ordering};
|
|
|
|
use core::task::Poll;
|
|
|
|
|
|
|
|
use embassy_futures::poll_once;
|
|
|
|
use embassy_stm32::ipcc::Ipcc;
|
|
|
|
use embassy_sync::waitqueue::AtomicWaker;
|
|
|
|
|
2023-06-20 04:17:31 +02:00
|
|
|
use crate::channels;
|
2023-06-19 01:51:14 +02:00
|
|
|
use crate::cmd::CmdPacket;
|
|
|
|
use crate::consts::TlPacketType;
|
|
|
|
use crate::evt::{EvtBox, EvtPacket};
|
|
|
|
use crate::tables::{
|
|
|
|
Mac802_15_4Table, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, TL_MAC_802_15_4_TABLE,
|
|
|
|
};
|
|
|
|
|
|
|
|
static MAC_WAKER: AtomicWaker = AtomicWaker::new();
|
|
|
|
static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false);
|
|
|
|
|
|
|
|
pub struct Mac {
|
|
|
|
phantom: PhantomData<Mac>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Mac {
|
|
|
|
pub(crate) fn new() -> Self {
|
|
|
|
unsafe {
|
|
|
|
TL_MAC_802_15_4_TABLE.as_mut_ptr().write_volatile(Mac802_15_4Table {
|
|
|
|
p_cmdrsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(),
|
|
|
|
p_notack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(),
|
|
|
|
evt_queue: ptr::null_mut(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Self { phantom: PhantomData }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// SAFETY: passing a pointer to something other than a managed event packet is UB
|
|
|
|
pub(crate) unsafe fn drop_event_packet(_: *mut EvtPacket) {
|
|
|
|
// Write the ack
|
2023-06-20 04:17:31 +02:00
|
|
|
CmdPacket::write_into(
|
|
|
|
MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _,
|
|
|
|
TlPacketType::OtAck,
|
|
|
|
0,
|
|
|
|
&[],
|
|
|
|
);
|
2023-06-19 01:51:14 +02:00
|
|
|
|
|
|
|
// Clear the rx flag
|
|
|
|
let _ = poll_once(Ipcc::receive::<bool>(
|
|
|
|
channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL,
|
|
|
|
|| None,
|
|
|
|
));
|
|
|
|
|
|
|
|
// Allow a new read call
|
|
|
|
MAC_EVT_OUT.store(false, Ordering::SeqCst);
|
|
|
|
MAC_WAKER.wake();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `HW_IPCC_MAC_802_15_4_EvtNot`
|
|
|
|
///
|
|
|
|
/// This function will stall if the previous `EvtBox` has not been dropped
|
|
|
|
pub async fn read(&self) -> EvtBox {
|
|
|
|
// Wait for the last event box to be dropped
|
|
|
|
poll_fn(|cx| {
|
|
|
|
MAC_WAKER.register(cx.waker());
|
|
|
|
if MAC_EVT_OUT.load(Ordering::SeqCst) {
|
|
|
|
Poll::Pending
|
|
|
|
} else {
|
|
|
|
Poll::Ready(())
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
|
|
|
|
// Return a new event box
|
|
|
|
Ipcc::receive(channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, || unsafe {
|
|
|
|
// The closure is not async, therefore the closure must execute to completion (cannot be dropped)
|
|
|
|
// Therefore, the event box is guaranteed to be cleaned up if it's not leaked
|
|
|
|
MAC_EVT_OUT.store(true, Ordering::SeqCst);
|
|
|
|
|
|
|
|
Some(EvtBox::new(MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _))
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `HW_IPCC_MAC_802_15_4_CmdEvtNot`
|
|
|
|
pub async fn write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 {
|
|
|
|
self.write(opcode, payload).await;
|
|
|
|
Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket;
|
|
|
|
let p_mac_rsp_evt = &((*p_event_packet).evt_serial.evt.payload) as *const u8;
|
|
|
|
|
|
|
|
ptr::read_volatile(p_mac_rsp_evt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `TL_MAC_802_15_4_SendCmd`
|
|
|
|
pub async fn write(&self, opcode: u16, payload: &[u8]) {
|
|
|
|
Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe {
|
|
|
|
CmdPacket::write_into(
|
|
|
|
MAC_802_15_4_CMD_BUFFER.as_mut_ptr(),
|
|
|
|
TlPacketType::OtCmd,
|
|
|
|
opcode,
|
|
|
|
payload,
|
|
|
|
);
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
}
|