diff options
Diffstat (limited to 'embassy-stm32-wpan/src/wb55/sub/mac.rs')
| -rw-r--r-- | embassy-stm32-wpan/src/wb55/sub/mac.rs | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/embassy-stm32-wpan/src/wb55/sub/mac.rs b/embassy-stm32-wpan/src/wb55/sub/mac.rs new file mode 100644 index 000000000..ce2903e61 --- /dev/null +++ b/embassy-stm32-wpan/src/wb55/sub/mac.rs | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::ptr; | ||
| 3 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 4 | use core::task::Poll; | ||
| 5 | |||
| 6 | use embassy_futures::poll_once; | ||
| 7 | use embassy_stm32::ipcc::{Ipcc, IpccRxChannel, IpccTxChannel}; | ||
| 8 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 9 | |||
| 10 | use crate::cmd::CmdPacket; | ||
| 11 | use crate::consts::TlPacketType; | ||
| 12 | use crate::evt; | ||
| 13 | use crate::evt::{EvtBox, EvtPacket}; | ||
| 14 | use crate::mac::commands::MacCommand; | ||
| 15 | use crate::mac::event::MacEvent; | ||
| 16 | use crate::mac::typedefs::MacError; | ||
| 17 | use crate::tables::{MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER}; | ||
| 18 | use crate::unsafe_linked_list::LinkedListNode; | ||
| 19 | |||
| 20 | static MAC_WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 21 | static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false); | ||
| 22 | |||
| 23 | pub struct Mac<'a> { | ||
| 24 | ipcc_mac_802_15_4_cmd_rsp_channel: IpccTxChannel<'a>, | ||
| 25 | ipcc_mac_802_15_4_notification_ack_channel: IpccRxChannel<'a>, | ||
| 26 | } | ||
| 27 | |||
| 28 | impl<'a> Mac<'a> { | ||
| 29 | pub(crate) fn new( | ||
| 30 | ipcc_mac_802_15_4_cmd_rsp_channel: IpccTxChannel<'a>, | ||
| 31 | ipcc_mac_802_15_4_notification_ack_channel: IpccRxChannel<'a>, | ||
| 32 | ) -> Self { | ||
| 33 | use crate::tables::{ | ||
| 34 | MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, Mac802_15_4Table, TL_MAC_802_15_4_TABLE, | ||
| 35 | TL_TRACES_TABLE, TRACES_EVT_QUEUE, TracesTable, | ||
| 36 | }; | ||
| 37 | |||
| 38 | unsafe { | ||
| 39 | LinkedListNode::init_head(TRACES_EVT_QUEUE.as_mut_ptr() as *mut _); | ||
| 40 | |||
| 41 | TL_TRACES_TABLE.as_mut_ptr().write_volatile(TracesTable { | ||
| 42 | traces_queue: TRACES_EVT_QUEUE.as_ptr() as *const _, | ||
| 43 | }); | ||
| 44 | |||
| 45 | TL_MAC_802_15_4_TABLE.as_mut_ptr().write_volatile(Mac802_15_4Table { | ||
| 46 | p_cmdrsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(), | ||
| 47 | p_notack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(), | ||
| 48 | evt_queue: core::ptr::null_mut(), | ||
| 49 | }); | ||
| 50 | }; | ||
| 51 | |||
| 52 | Self { | ||
| 53 | ipcc_mac_802_15_4_cmd_rsp_channel, | ||
| 54 | ipcc_mac_802_15_4_notification_ack_channel, | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | pub const fn split(self) -> (MacRx<'a>, MacTx<'a>) { | ||
| 59 | ( | ||
| 60 | MacRx { | ||
| 61 | ipcc_mac_802_15_4_notification_ack_channel: self.ipcc_mac_802_15_4_notification_ack_channel, | ||
| 62 | }, | ||
| 63 | MacTx { | ||
| 64 | ipcc_mac_802_15_4_cmd_rsp_channel: self.ipcc_mac_802_15_4_cmd_rsp_channel, | ||
| 65 | }, | ||
| 66 | ) | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | pub struct MacTx<'a> { | ||
| 71 | ipcc_mac_802_15_4_cmd_rsp_channel: IpccTxChannel<'a>, | ||
| 72 | } | ||
| 73 | |||
| 74 | impl<'a> MacTx<'a> { | ||
| 75 | /// `HW_IPCC_MAC_802_15_4_CmdEvtNot` | ||
| 76 | pub async fn tl_write_and_get_response(&mut self, opcode: u16, payload: &[u8]) -> u8 { | ||
| 77 | self.tl_write(opcode, payload).await; | ||
| 78 | self.ipcc_mac_802_15_4_cmd_rsp_channel.flush().await; | ||
| 79 | |||
| 80 | unsafe { | ||
| 81 | let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket; | ||
| 82 | let p_mac_rsp_evt = &((*p_event_packet).evt_serial.evt.payload) as *const u8; | ||
| 83 | |||
| 84 | ptr::read_volatile(p_mac_rsp_evt) | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | /// `TL_MAC_802_15_4_SendCmd` | ||
| 89 | pub async fn tl_write(&mut self, opcode: u16, payload: &[u8]) { | ||
| 90 | self.ipcc_mac_802_15_4_cmd_rsp_channel | ||
| 91 | .send(|| unsafe { | ||
| 92 | CmdPacket::write_into( | ||
| 93 | MAC_802_15_4_CMD_BUFFER.as_mut_ptr(), | ||
| 94 | TlPacketType::MacCmd, | ||
| 95 | opcode, | ||
| 96 | payload, | ||
| 97 | ); | ||
| 98 | }) | ||
| 99 | .await; | ||
| 100 | } | ||
| 101 | |||
| 102 | pub async fn send_command<T>(&mut self, cmd: &T) -> Result<(), MacError> | ||
| 103 | where | ||
| 104 | T: MacCommand, | ||
| 105 | { | ||
| 106 | let response = self.tl_write_and_get_response(T::OPCODE as u16, cmd.payload()).await; | ||
| 107 | |||
| 108 | if response == 0x00 { | ||
| 109 | Ok(()) | ||
| 110 | } else { | ||
| 111 | Err(MacError::from(response)) | ||
| 112 | } | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | pub struct MacRx<'a> { | ||
| 117 | ipcc_mac_802_15_4_notification_ack_channel: IpccRxChannel<'a>, | ||
| 118 | } | ||
| 119 | |||
| 120 | impl<'a> MacRx<'a> { | ||
| 121 | /// `HW_IPCC_MAC_802_15_4_EvtNot` | ||
| 122 | /// | ||
| 123 | /// This function will stall if the previous `EvtBox` has not been dropped | ||
| 124 | pub async fn tl_read(&mut self) -> EvtBox<MacRx<'a>> { | ||
| 125 | // Wait for the last event box to be dropped | ||
| 126 | poll_fn(|cx| { | ||
| 127 | MAC_WAKER.register(cx.waker()); | ||
| 128 | if MAC_EVT_OUT.load(Ordering::Acquire) { | ||
| 129 | Poll::Pending | ||
| 130 | } else { | ||
| 131 | Poll::Ready(()) | ||
| 132 | } | ||
| 133 | }) | ||
| 134 | .await; | ||
| 135 | |||
| 136 | // Return a new event box | ||
| 137 | self.ipcc_mac_802_15_4_notification_ack_channel | ||
| 138 | .receive(|| unsafe { | ||
| 139 | // The closure is not async, therefore the closure must execute to completion (cannot be dropped) | ||
| 140 | // Therefore, the event box is guaranteed to be cleaned up if it's not leaked | ||
| 141 | MAC_EVT_OUT.store(true, Ordering::SeqCst); | ||
| 142 | |||
| 143 | Some(EvtBox::new(MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _)) | ||
| 144 | }) | ||
| 145 | .await | ||
| 146 | } | ||
| 147 | |||
| 148 | pub async fn read<'b>(&mut self) -> Result<MacEvent<'b>, ()> { | ||
| 149 | MacEvent::new(self.tl_read().await) | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | impl<'a> evt::MemoryManager for MacRx<'a> { | ||
| 154 | /// SAFETY: passing a pointer to something other than a managed event packet is UB | ||
| 155 | unsafe fn drop_event_packet(_: *mut EvtPacket) { | ||
| 156 | trace!("mac drop event"); | ||
| 157 | |||
| 158 | // Write the ack | ||
| 159 | CmdPacket::write_into( | ||
| 160 | MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _, | ||
| 161 | TlPacketType::OtAck, | ||
| 162 | 0, | ||
| 163 | &[], | ||
| 164 | ); | ||
| 165 | |||
| 166 | // Clear the rx flag | ||
| 167 | let _ = poll_once(Ipcc::receive::<()>(3, || None)); | ||
| 168 | |||
| 169 | // Allow a new read call | ||
| 170 | MAC_EVT_OUT.store(false, Ordering::Release); | ||
| 171 | MAC_WAKER.wake(); | ||
| 172 | } | ||
| 173 | } | ||
