diff options
| author | goueslati <[email protected]> | 2023-06-12 12:27:51 +0100 |
|---|---|---|
| committer | goueslati <[email protected]> | 2023-06-12 12:27:51 +0100 |
| commit | ca8957da435eb91242fa33eb986e80a33bbc4da0 (patch) | |
| tree | 89b66bdff52630cd4ef1d609122c2b04417ccd73 /embassy-stm32-wpan/src/lib.rs | |
| parent | ce1d72c609ae1e04410e68458ec3d6c36c7dae27 (diff) | |
stm32/ipcc: move tl_mbox into `embassy-stm32-wpan`
Diffstat (limited to 'embassy-stm32-wpan/src/lib.rs')
| -rw-r--r-- | embassy-stm32-wpan/src/lib.rs | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs new file mode 100644 index 000000000..b3206428e --- /dev/null +++ b/embassy-stm32-wpan/src/lib.rs | |||
| @@ -0,0 +1,266 @@ | |||
| 1 | #![no_std] | ||
| 2 | |||
| 3 | // This must go FIRST so that all the other modules see its macros. | ||
| 4 | pub mod fmt; | ||
| 5 | |||
| 6 | use core::mem::MaybeUninit; | ||
| 7 | |||
| 8 | use cmd::CmdPacket; | ||
| 9 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 10 | use embassy_futures::block_on; | ||
| 11 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | ||
| 12 | use embassy_stm32::interrupt; | ||
| 13 | use embassy_stm32::ipcc::{Config, Ipcc}; | ||
| 14 | use embassy_stm32::peripherals::IPCC; | ||
| 15 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 16 | use embassy_sync::channel::Channel; | ||
| 17 | use embassy_sync::signal::Signal; | ||
| 18 | use evt::{CcEvt, EvtBox}; | ||
| 19 | use tables::{ | ||
| 20 | BleTable, DeviceInfoTable, Mac802_15_4Table, MemManagerTable, RefTable, SysTable, ThreadTable, TracesTable, | ||
| 21 | WirelessFwInfoTable, | ||
| 22 | }; | ||
| 23 | use unsafe_linked_list::LinkedListNode; | ||
| 24 | |||
| 25 | pub mod ble; | ||
| 26 | pub mod channels; | ||
| 27 | pub mod cmd; | ||
| 28 | pub mod consts; | ||
| 29 | pub mod evt; | ||
| 30 | pub mod mm; | ||
| 31 | pub mod rc; | ||
| 32 | pub mod shci; | ||
| 33 | pub mod sys; | ||
| 34 | pub mod tables; | ||
| 35 | pub mod unsafe_linked_list; | ||
| 36 | |||
| 37 | /// Interrupt handler. | ||
| 38 | pub struct ReceiveInterruptHandler {} | ||
| 39 | |||
| 40 | impl interrupt::Handler<interrupt::IPCC_C1_RX> for ReceiveInterruptHandler { | ||
| 41 | unsafe fn on_interrupt() { | ||
| 42 | if Ipcc::is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) { | ||
| 43 | debug!("RX SYS evt"); | ||
| 44 | sys::Sys::evt_handler(); | ||
| 45 | } else if Ipcc::is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) { | ||
| 46 | debug!("RX BLE evt"); | ||
| 47 | ble::Ble::evt_handler(); | ||
| 48 | } | ||
| 49 | |||
| 50 | STATE.signal(()); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | pub struct TransmitInterruptHandler {} | ||
| 55 | |||
| 56 | impl interrupt::Handler<interrupt::IPCC_C1_TX> for TransmitInterruptHandler { | ||
| 57 | unsafe fn on_interrupt() { | ||
| 58 | if Ipcc::is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) { | ||
| 59 | debug!("TX SYS cmd rsp"); | ||
| 60 | let cc = sys::Sys::cmd_evt_handler(); | ||
| 61 | |||
| 62 | LAST_CC_EVT.signal(cc); | ||
| 63 | } else if Ipcc::is_tx_pending(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL) { | ||
| 64 | debug!("TX MM release"); | ||
| 65 | mm::MemoryManager::free_buf_handler(); | ||
| 66 | } else if Ipcc::is_tx_pending(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL) { | ||
| 67 | debug!("TX HCI acl"); | ||
| 68 | ble::Ble::acl_data_handler(); | ||
| 69 | } | ||
| 70 | |||
| 71 | STATE.signal(()); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | #[link_section = "TL_REF_TABLE"] | ||
| 76 | pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit(); | ||
| 77 | |||
| 78 | #[link_section = "MB_MEM1"] | ||
| 79 | static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit(); | ||
| 80 | |||
| 81 | #[link_section = "MB_MEM1"] | ||
| 82 | static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit(); | ||
| 83 | |||
| 84 | #[link_section = "MB_MEM1"] | ||
| 85 | static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit(); | ||
| 86 | |||
| 87 | #[link_section = "MB_MEM1"] | ||
| 88 | static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit(); | ||
| 89 | |||
| 90 | #[link_section = "MB_MEM1"] | ||
| 91 | static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit(); | ||
| 92 | |||
| 93 | #[link_section = "MB_MEM1"] | ||
| 94 | static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit(); | ||
| 95 | |||
| 96 | #[link_section = "MB_MEM1"] | ||
| 97 | static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit(); | ||
| 98 | |||
| 99 | #[link_section = "MB_MEM2"] | ||
| 100 | static mut FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 101 | |||
| 102 | // Not in shared RAM | ||
| 103 | static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 104 | |||
| 105 | #[allow(dead_code)] // Not used currently but reserved | ||
| 106 | #[link_section = "MB_MEM2"] | ||
| 107 | static mut TRACES_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 108 | |||
| 109 | type PacketHeader = LinkedListNode; | ||
| 110 | |||
| 111 | const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::<PacketHeader>(); | ||
| 112 | const TL_EVT_HEADER_SIZE: usize = 3; | ||
| 113 | const TL_CS_EVT_SIZE: usize = core::mem::size_of::<evt::CsEvt>(); | ||
| 114 | |||
| 115 | #[link_section = "MB_MEM2"] | ||
| 116 | static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> = | ||
| 117 | MaybeUninit::uninit(); | ||
| 118 | |||
| 119 | #[link_section = "MB_MEM2"] | ||
| 120 | static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 121 | |||
| 122 | #[link_section = "MB_MEM2"] | ||
| 123 | static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 124 | |||
| 125 | #[link_section = "MB_MEM2"] | ||
| 126 | pub static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit(); | ||
| 127 | |||
| 128 | /** | ||
| 129 | * Queue length of BLE Event | ||
| 130 | * This parameter defines the number of asynchronous events that can be stored in the HCI layer before | ||
| 131 | * being reported to the application. When a command is sent to the BLE core coprocessor, the HCI layer | ||
| 132 | * is waiting for the event with the Num_HCI_Command_Packets set to 1. The receive queue shall be large | ||
| 133 | * enough to store all asynchronous events received in between. | ||
| 134 | * When CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE is set to 27, this allow to store three 255 bytes long asynchronous events | ||
| 135 | * between the HCI command and its event. | ||
| 136 | * This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is to small, | ||
| 137 | * the system may hang if the queue is full with asynchronous events and the HCI layer is still waiting | ||
| 138 | * for a CC/CS event, In that case, the notification TL_BLE_HCI_ToNot() is called to indicate | ||
| 139 | * to the application a HCI command did not receive its command event within 30s (Default HCI Timeout). | ||
| 140 | */ | ||
| 141 | const CFG_TLBLE_EVT_QUEUE_LENGTH: usize = 5; | ||
| 142 | const CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255; | ||
| 143 | const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE; | ||
| 144 | |||
| 145 | const fn divc(x: usize, y: usize) -> usize { | ||
| 146 | ((x) + (y) - 1) / (y) | ||
| 147 | } | ||
| 148 | |||
| 149 | const POOL_SIZE: usize = CFG_TLBLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4); | ||
| 150 | |||
| 151 | #[link_section = "MB_MEM2"] | ||
| 152 | static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit(); | ||
| 153 | |||
| 154 | #[link_section = "MB_MEM2"] | ||
| 155 | static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = | ||
| 156 | MaybeUninit::uninit(); | ||
| 157 | |||
| 158 | #[link_section = "MB_MEM2"] | ||
| 159 | static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = | ||
| 160 | MaybeUninit::uninit(); | ||
| 161 | |||
| 162 | #[link_section = "MB_MEM2"] | ||
| 163 | static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit(); | ||
| 164 | |||
| 165 | #[link_section = "MB_MEM2"] | ||
| 166 | // fuck these "magic" numbers from ST ---v---v | ||
| 167 | static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit(); | ||
| 168 | |||
| 169 | /// current event that is produced during IPCC IRQ handler execution | ||
| 170 | /// on SYS channel | ||
| 171 | static EVT_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 32> = Channel::new(); | ||
| 172 | |||
| 173 | /// last received Command Complete event | ||
| 174 | static LAST_CC_EVT: Signal<CriticalSectionRawMutex, CcEvt> = Signal::new(); | ||
| 175 | |||
| 176 | static STATE: Signal<CriticalSectionRawMutex, ()> = Signal::new(); | ||
| 177 | |||
| 178 | pub struct TlMbox<'d> { | ||
| 179 | _ipcc: PeripheralRef<'d, IPCC>, | ||
| 180 | } | ||
| 181 | |||
| 182 | impl<'d> TlMbox<'d> { | ||
| 183 | pub fn init( | ||
| 184 | ipcc: impl Peripheral<P = IPCC> + 'd, | ||
| 185 | _irqs: impl interrupt::Binding<interrupt::IPCC_C1_RX, ReceiveInterruptHandler> | ||
| 186 | + interrupt::Binding<interrupt::IPCC_C1_TX, TransmitInterruptHandler>, | ||
| 187 | config: Config, | ||
| 188 | ) -> Self { | ||
| 189 | into_ref!(ipcc); | ||
| 190 | |||
| 191 | unsafe { | ||
| 192 | TL_REF_TABLE = MaybeUninit::new(RefTable { | ||
| 193 | device_info_table: TL_DEVICE_INFO_TABLE.as_mut_ptr(), | ||
| 194 | ble_table: TL_BLE_TABLE.as_ptr(), | ||
| 195 | thread_table: TL_THREAD_TABLE.as_ptr(), | ||
| 196 | sys_table: TL_SYS_TABLE.as_ptr(), | ||
| 197 | mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(), | ||
| 198 | traces_table: TL_TRACES_TABLE.as_ptr(), | ||
| 199 | mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(), | ||
| 200 | }); | ||
| 201 | |||
| 202 | TL_SYS_TABLE = MaybeUninit::zeroed(); | ||
| 203 | TL_DEVICE_INFO_TABLE = MaybeUninit::zeroed(); | ||
| 204 | TL_BLE_TABLE = MaybeUninit::zeroed(); | ||
| 205 | TL_THREAD_TABLE = MaybeUninit::zeroed(); | ||
| 206 | TL_MEM_MANAGER_TABLE = MaybeUninit::zeroed(); | ||
| 207 | TL_TRACES_TABLE = MaybeUninit::zeroed(); | ||
| 208 | TL_MAC_802_15_4_TABLE = MaybeUninit::zeroed(); | ||
| 209 | |||
| 210 | EVT_POOL = MaybeUninit::zeroed(); | ||
| 211 | SYS_SPARE_EVT_BUF = MaybeUninit::zeroed(); | ||
| 212 | BLE_SPARE_EVT_BUF = MaybeUninit::zeroed(); | ||
| 213 | |||
| 214 | CS_BUFFER = MaybeUninit::zeroed(); | ||
| 215 | BLE_CMD_BUFFER = MaybeUninit::zeroed(); | ||
| 216 | HCI_ACL_DATA_BUFFER = MaybeUninit::zeroed(); | ||
| 217 | } | ||
| 218 | |||
| 219 | Ipcc::enable(config); | ||
| 220 | |||
| 221 | sys::Sys::enable(); | ||
| 222 | ble::Ble::enable(); | ||
| 223 | mm::MemoryManager::enable(); | ||
| 224 | |||
| 225 | // enable interrupts | ||
| 226 | interrupt::IPCC_C1_RX::unpend(); | ||
| 227 | interrupt::IPCC_C1_TX::unpend(); | ||
| 228 | |||
| 229 | unsafe { interrupt::IPCC_C1_RX::enable() }; | ||
| 230 | unsafe { interrupt::IPCC_C1_TX::enable() }; | ||
| 231 | |||
| 232 | STATE.reset(); | ||
| 233 | |||
| 234 | Self { _ipcc: ipcc } | ||
| 235 | } | ||
| 236 | |||
| 237 | /// Returns CPU2 wireless firmware information (if present). | ||
| 238 | pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> { | ||
| 239 | let info = unsafe { &(*(*TL_REF_TABLE.as_ptr()).device_info_table).wireless_fw_info_table }; | ||
| 240 | |||
| 241 | // Zero version indicates that CPU2 wasn't active and didn't fill the information table | ||
| 242 | if info.version != 0 { | ||
| 243 | Some(*info) | ||
| 244 | } else { | ||
| 245 | None | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | /// picks single [`EvtBox`] from internal event queue. | ||
| 250 | /// | ||
| 251 | /// Internal event queu is populated in IPCC_RX_IRQ handler | ||
| 252 | pub fn dequeue_event(&mut self) -> Option<EvtBox> { | ||
| 253 | EVT_CHANNEL.try_recv().ok() | ||
| 254 | } | ||
| 255 | |||
| 256 | /// retrieves last Command Complete event and removes it from mailbox | ||
| 257 | pub fn pop_last_cc_evt(&mut self) -> Option<CcEvt> { | ||
| 258 | if LAST_CC_EVT.signaled() { | ||
| 259 | let cc = block_on(LAST_CC_EVT.wait()); | ||
| 260 | LAST_CC_EVT.reset(); | ||
| 261 | Some(cc) | ||
| 262 | } else { | ||
| 263 | None | ||
| 264 | } | ||
| 265 | } | ||
| 266 | } | ||
