diff options
| author | goueslati <[email protected]> | 2023-05-15 10:25:02 +0100 |
|---|---|---|
| committer | goueslati <[email protected]> | 2023-05-15 10:25:02 +0100 |
| commit | d97724cca3164250118c732759f403f4f94d4629 (patch) | |
| tree | 10a69d2f4fd843a08b3c75fa94afc223087d6350 | |
| parent | 3810fe6a2058d04054c7242216a7bc9d2993667b (diff) | |
tl_mbox read and write
| -rw-r--r-- | embassy-stm32/src/ipcc.rs | 15 | ||||
| -rw-r--r-- | embassy-stm32/src/tl_mbox/ble.rs | 48 | ||||
| -rw-r--r-- | embassy-stm32/src/tl_mbox/channels.rs | 8 | ||||
| -rw-r--r-- | embassy-stm32/src/tl_mbox/consts.rs | 53 | ||||
| -rw-r--r-- | embassy-stm32/src/tl_mbox/evt.rs | 163 | ||||
| -rw-r--r-- | embassy-stm32/src/tl_mbox/mm.rs | 47 | ||||
| -rw-r--r-- | embassy-stm32/src/tl_mbox/mod.rs | 77 | ||||
| -rw-r--r-- | embassy-stm32/src/tl_mbox/shci.rs | 101 | ||||
| -rw-r--r-- | embassy-stm32/src/tl_mbox/sys.rs | 69 | ||||
| -rw-r--r-- | examples/stm32wb/src/bin/tl_mbox.rs | 6 | ||||
| -rw-r--r-- | examples/stm32wb/src/bin/tl_mbox_tx_rx.rs | 96 |
11 files changed, 661 insertions, 22 deletions
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 903aeca30..9af5f171f 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs | |||
| @@ -158,6 +158,10 @@ impl<'d> Ipcc<'d> { | |||
| 158 | pub fn is_rx_pending(&self, channel: IpccChannel) -> bool { | 158 | pub fn is_rx_pending(&self, channel: IpccChannel) -> bool { |
| 159 | self.c2_is_active_flag(channel) && self.c1_get_rx_channel(channel) | 159 | self.c2_is_active_flag(channel) && self.c1_get_rx_channel(channel) |
| 160 | } | 160 | } |
| 161 | |||
| 162 | pub fn as_mut_ptr(&self) -> *mut Self { | ||
| 163 | unsafe { &mut core::ptr::read(self) as *mut _ } | ||
| 164 | } | ||
| 161 | } | 165 | } |
| 162 | 166 | ||
| 163 | impl sealed::Instance for crate::peripherals::IPCC { | 167 | impl sealed::Instance for crate::peripherals::IPCC { |
| @@ -176,3 +180,14 @@ unsafe fn _configure_pwr() { | |||
| 176 | // set RF wake-up clock = LSE | 180 | // set RF wake-up clock = LSE |
| 177 | rcc.csr().modify(|w| w.set_rfwkpsel(0b01)); | 181 | rcc.csr().modify(|w| w.set_rfwkpsel(0b01)); |
| 178 | } | 182 | } |
| 183 | |||
| 184 | // TODO: if anyone has a better idea, please let me know | ||
| 185 | /// extension trait that constrains the [`Ipcc`] peripheral | ||
| 186 | pub trait IpccExt<'d> { | ||
| 187 | fn constrain(self) -> Ipcc<'d>; | ||
| 188 | } | ||
| 189 | impl<'d> IpccExt<'d> for IPCC { | ||
| 190 | fn constrain(self) -> Ipcc<'d> { | ||
| 191 | Ipcc { _peri: self.into_ref() } | ||
| 192 | } | ||
| 193 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/ble.rs b/embassy-stm32/src/tl_mbox/ble.rs index a2c0758d1..a285e314c 100644 --- a/embassy-stm32/src/tl_mbox/ble.rs +++ b/embassy-stm32/src/tl_mbox/ble.rs | |||
| @@ -1,13 +1,22 @@ | |||
| 1 | use core::mem::MaybeUninit; | 1 | use core::mem::MaybeUninit; |
| 2 | 2 | ||
| 3 | use super::unsafe_linked_list::LST_init_head; | 3 | use embassy_futures::block_on; |
| 4 | use super::{channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE}; | 4 | |
| 5 | use super::cmd::CmdSerial; | ||
| 6 | use super::consts::TlPacketType; | ||
| 7 | use super::evt::EvtBox; | ||
| 8 | use super::unsafe_linked_list::{LST_init_head, LST_is_empty, LST_remove_head}; | ||
| 9 | use super::{ | ||
| 10 | channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE, TL_CHANNEL, | ||
| 11 | TL_REF_TABLE, | ||
| 12 | }; | ||
| 5 | use crate::ipcc::Ipcc; | 13 | use crate::ipcc::Ipcc; |
| 14 | use crate::tl_mbox::cmd::CmdPacket; | ||
| 6 | 15 | ||
| 7 | pub struct Ble; | 16 | pub struct Ble; |
| 8 | 17 | ||
| 9 | impl Ble { | 18 | impl Ble { |
| 10 | pub fn new(ipcc: &mut Ipcc) -> Self { | 19 | pub(crate) fn new(ipcc: &mut Ipcc) -> Self { |
| 11 | unsafe { | 20 | unsafe { |
| 12 | LST_init_head(EVT_QUEUE.as_mut_ptr()); | 21 | LST_init_head(EVT_QUEUE.as_mut_ptr()); |
| 13 | 22 | ||
| @@ -23,4 +32,37 @@ impl Ble { | |||
| 23 | 32 | ||
| 24 | Ble | 33 | Ble |
| 25 | } | 34 | } |
| 35 | |||
| 36 | pub(crate) fn evt_handler(ipcc: &mut Ipcc) { | ||
| 37 | unsafe { | ||
| 38 | let mut node_ptr = core::ptr::null_mut(); | ||
| 39 | let node_ptr_ptr: *mut _ = &mut node_ptr; | ||
| 40 | |||
| 41 | while !LST_is_empty(EVT_QUEUE.as_mut_ptr()) { | ||
| 42 | LST_remove_head(EVT_QUEUE.as_mut_ptr(), node_ptr_ptr); | ||
| 43 | |||
| 44 | let event = node_ptr.cast(); | ||
| 45 | let event = EvtBox::new(event); | ||
| 46 | |||
| 47 | block_on(TL_CHANNEL.send(event)); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | ipcc.c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL); | ||
| 52 | } | ||
| 53 | |||
| 54 | pub(crate) fn send_cmd(ipcc: &mut Ipcc, buf: &[u8]) { | ||
| 55 | unsafe { | ||
| 56 | let pcmd_buffer: *mut CmdPacket = (*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer; | ||
| 57 | let pcmd_serial: *mut CmdSerial = &mut (*pcmd_buffer).cmd_serial; | ||
| 58 | let pcmd_serial_buf: *mut u8 = pcmd_serial.cast(); | ||
| 59 | |||
| 60 | core::ptr::copy(buf.as_ptr(), pcmd_serial_buf, buf.len()); | ||
| 61 | |||
| 62 | let mut cmd_packet = &mut *(*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer; | ||
| 63 | cmd_packet.cmd_serial.ty = TlPacketType::BleCmd as u8; | ||
| 64 | } | ||
| 65 | |||
| 66 | ipcc.c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL); | ||
| 67 | } | ||
| 26 | } | 68 | } |
diff --git a/embassy-stm32/src/tl_mbox/channels.rs b/embassy-stm32/src/tl_mbox/channels.rs index 1dde5d61c..aaa6ce177 100644 --- a/embassy-stm32/src/tl_mbox/channels.rs +++ b/embassy-stm32/src/tl_mbox/channels.rs | |||
| @@ -52,9 +52,9 @@ | |||
| 52 | pub mod cpu1 { | 52 | pub mod cpu1 { |
| 53 | use crate::ipcc::IpccChannel; | 53 | use crate::ipcc::IpccChannel; |
| 54 | 54 | ||
| 55 | #[allow(dead_code)] // Not used currently but reserved | 55 | // Not used currently but reserved |
| 56 | pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1; | 56 | pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1; |
| 57 | #[allow(dead_code)] // Not used currently but reserved | 57 | // Not used currently but reserved |
| 58 | pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2; | 58 | pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2; |
| 59 | #[allow(dead_code)] // Not used currently but reserved | 59 | #[allow(dead_code)] // Not used currently but reserved |
| 60 | pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; | 60 | pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; |
| @@ -62,7 +62,7 @@ pub mod cpu1 { | |||
| 62 | pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3; | 62 | pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3; |
| 63 | #[allow(dead_code)] // Not used currently but reserved | 63 | #[allow(dead_code)] // Not used currently but reserved |
| 64 | pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; | 64 | pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; |
| 65 | #[allow(dead_code)] // Not used currently but reserved | 65 | // Not used currently but reserved |
| 66 | pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4; | 66 | pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4; |
| 67 | #[allow(dead_code)] // Not used currently but reserved | 67 | #[allow(dead_code)] // Not used currently but reserved |
| 68 | pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; | 68 | pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; |
| @@ -88,7 +88,7 @@ pub mod cpu2 { | |||
| 88 | #[allow(dead_code)] // Not used currently but reserved | 88 | #[allow(dead_code)] // Not used currently but reserved |
| 89 | pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; | 89 | pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; |
| 90 | #[allow(dead_code)] // Not used currently but reserved | 90 | #[allow(dead_code)] // Not used currently but reserved |
| 91 | pub const IPCC_BLE_LLDÇM0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; | 91 | pub const IPCC_BLE_LLD_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; |
| 92 | #[allow(dead_code)] // Not used currently but reserved | 92 | #[allow(dead_code)] // Not used currently but reserved |
| 93 | pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4; | 93 | pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4; |
| 94 | #[allow(dead_code)] // Not used currently but reserved | 94 | #[allow(dead_code)] // Not used currently but reserved |
diff --git a/embassy-stm32/src/tl_mbox/consts.rs b/embassy-stm32/src/tl_mbox/consts.rs new file mode 100644 index 000000000..e16a26cd0 --- /dev/null +++ b/embassy-stm32/src/tl_mbox/consts.rs | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | #[derive(PartialEq)] | ||
| 2 | #[repr(C)] | ||
| 3 | pub enum TlPacketType { | ||
| 4 | BleCmd = 0x01, | ||
| 5 | AclData = 0x02, | ||
| 6 | BleEvt = 0x04, | ||
| 7 | |||
| 8 | OtCmd = 0x08, | ||
| 9 | OtRsp = 0x09, | ||
| 10 | CliCmd = 0x0A, | ||
| 11 | OtNot = 0x0C, | ||
| 12 | OtAck = 0x0D, | ||
| 13 | CliNot = 0x0E, | ||
| 14 | CliAck = 0x0F, | ||
| 15 | |||
| 16 | SysCmd = 0x10, | ||
| 17 | SysRsp = 0x11, | ||
| 18 | SysEvt = 0x12, | ||
| 19 | |||
| 20 | LocCmd = 0x20, | ||
| 21 | LocRsp = 0x21, | ||
| 22 | |||
| 23 | TracesApp = 0x40, | ||
| 24 | TracesWl = 0x41, | ||
| 25 | } | ||
| 26 | |||
| 27 | impl TryFrom<u8> for TlPacketType { | ||
| 28 | type Error = (); | ||
| 29 | |||
| 30 | fn try_from(value: u8) -> Result<Self, Self::Error> { | ||
| 31 | match value { | ||
| 32 | 0x01 => Ok(TlPacketType::BleCmd), | ||
| 33 | 0x02 => Ok(TlPacketType::AclData), | ||
| 34 | 0x04 => Ok(TlPacketType::BleEvt), | ||
| 35 | 0x08 => Ok(TlPacketType::OtCmd), | ||
| 36 | 0x09 => Ok(TlPacketType::OtRsp), | ||
| 37 | 0x0A => Ok(TlPacketType::CliCmd), | ||
| 38 | 0x0C => Ok(TlPacketType::OtNot), | ||
| 39 | 0x0D => Ok(TlPacketType::OtAck), | ||
| 40 | 0x0E => Ok(TlPacketType::CliNot), | ||
| 41 | 0x0F => Ok(TlPacketType::CliAck), | ||
| 42 | 0x10 => Ok(TlPacketType::SysCmd), | ||
| 43 | 0x11 => Ok(TlPacketType::SysRsp), | ||
| 44 | 0x12 => Ok(TlPacketType::SysEvt), | ||
| 45 | 0x20 => Ok(TlPacketType::LocCmd), | ||
| 46 | 0x21 => Ok(TlPacketType::LocRsp), | ||
| 47 | 0x40 => Ok(TlPacketType::TracesApp), | ||
| 48 | 0x41 => Ok(TlPacketType::TracesWl), | ||
| 49 | |||
| 50 | _ => Err(()), | ||
| 51 | } | ||
| 52 | } | ||
| 53 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/evt.rs b/embassy-stm32/src/tl_mbox/evt.rs index 4244db810..8ae2a2559 100644 --- a/embassy-stm32/src/tl_mbox/evt.rs +++ b/embassy-stm32/src/tl_mbox/evt.rs | |||
| @@ -1,3 +1,10 @@ | |||
| 1 | use core::mem::MaybeUninit; | ||
| 2 | |||
| 3 | use super::cmd::{AclDataPacket, AclDataSerial}; | ||
| 4 | use super::consts::TlPacketType; | ||
| 5 | use super::{PacketHeader, TL_EVT_HEADER_SIZE}; | ||
| 6 | use crate::tl_mbox::mm; | ||
| 7 | |||
| 1 | /// the payload of [`Evt`] for a command status event | 8 | /// the payload of [`Evt`] for a command status event |
| 2 | #[derive(Copy, Clone)] | 9 | #[derive(Copy, Clone)] |
| 3 | #[repr(C, packed)] | 10 | #[repr(C, packed)] |
| @@ -6,3 +13,159 @@ pub struct CsEvt { | |||
| 6 | pub num_cmd: u8, | 13 | pub num_cmd: u8, |
| 7 | pub cmd_code: u16, | 14 | pub cmd_code: u16, |
| 8 | } | 15 | } |
| 16 | |||
| 17 | /// the payload of [`Evt`] for a command complete event | ||
| 18 | #[derive(Clone, Copy, Default)] | ||
| 19 | #[repr(C, packed)] | ||
| 20 | pub struct CcEvt { | ||
| 21 | pub num_cmd: u8, | ||
| 22 | pub cmd_code: u8, | ||
| 23 | pub payload: [u8; 1], | ||
| 24 | } | ||
| 25 | |||
| 26 | #[derive(Clone, Copy, Default)] | ||
| 27 | #[repr(C, packed)] | ||
| 28 | pub struct Evt { | ||
| 29 | pub evt_code: u8, | ||
| 30 | pub payload_len: u8, | ||
| 31 | pub payload: [u8; 1], | ||
| 32 | } | ||
| 33 | |||
| 34 | #[derive(Clone, Copy, Default)] | ||
| 35 | #[repr(C, packed)] | ||
| 36 | pub struct EvtSerial { | ||
| 37 | pub kind: u8, | ||
| 38 | pub evt: Evt, | ||
| 39 | } | ||
| 40 | |||
| 41 | /// This format shall be used for all events (asynchronous and command response) reported | ||
| 42 | /// by the CPU2 except for the command response of a system command where the header is not there | ||
| 43 | /// and the format to be used shall be `EvtSerial`. | ||
| 44 | /// | ||
| 45 | /// ### Note: | ||
| 46 | /// Be careful that the asynchronous events reported by the CPU2 on the system channel do | ||
| 47 | /// include the header and shall use `EvtPacket` format. Only the command response format on the | ||
| 48 | /// system channel is different. | ||
| 49 | #[derive(Clone, Copy, Default)] | ||
| 50 | #[repr(C, packed)] | ||
| 51 | pub struct EvtPacket { | ||
| 52 | pub header: PacketHeader, | ||
| 53 | pub evt_serial: EvtSerial, | ||
| 54 | } | ||
| 55 | |||
| 56 | /// Smart pointer to the [`EvtPacket`] that will dispose of it automatically on drop | ||
| 57 | pub struct EvtBox { | ||
| 58 | ptr: *mut EvtPacket, | ||
| 59 | } | ||
| 60 | |||
| 61 | unsafe impl Send for EvtBox {} | ||
| 62 | impl EvtBox { | ||
| 63 | pub(super) fn new(ptr: *mut EvtPacket) -> Self { | ||
| 64 | Self { ptr } | ||
| 65 | } | ||
| 66 | |||
| 67 | /// Copies the event data from inner pointer and returns and event structure | ||
| 68 | pub fn evt(&self) -> EvtPacket { | ||
| 69 | let mut evt = MaybeUninit::uninit(); | ||
| 70 | unsafe { | ||
| 71 | self.ptr.copy_to(evt.as_mut_ptr(), 1); | ||
| 72 | evt.assume_init() | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | /// Returns the size of a buffer required to hold this event | ||
| 77 | pub fn size(&self) -> Result<usize, ()> { | ||
| 78 | unsafe { | ||
| 79 | let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?; | ||
| 80 | |||
| 81 | if evt_kind == TlPacketType::AclData { | ||
| 82 | let acl_data: *const AclDataPacket = self.ptr.cast(); | ||
| 83 | let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial; | ||
| 84 | |||
| 85 | Ok((*acl_serial).length as usize + 5) | ||
| 86 | } else { | ||
| 87 | let evt_data: *const EvtPacket = self.ptr.cast(); | ||
| 88 | let evt_serial: *const EvtSerial = &(*evt_data).evt_serial; | ||
| 89 | |||
| 90 | Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE) | ||
| 91 | } | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | /// writes an underlying [`EvtPacket`] into the provided buffer. Returns the number of bytes that were | ||
| 96 | /// written. Returns an error if event kind is unkown or if provided buffer size is not enough | ||
| 97 | pub fn copy_into_slice(&self, buf: &mut [u8]) -> Result<usize, ()> { | ||
| 98 | // TODO: double check this | ||
| 99 | // unsafe { | ||
| 100 | // let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?; | ||
| 101 | |||
| 102 | // if let TlPacketType::AclData = evt_kind { | ||
| 103 | // let acl_data: *const AclDataPacket = self.ptr.cast(); | ||
| 104 | // let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial; | ||
| 105 | // let acl_serial_buf: *const u8 = acl_serial.cast(); | ||
| 106 | |||
| 107 | // let len = (*acl_serial).length as usize + 5; | ||
| 108 | // if len > buf.len() { | ||
| 109 | // return Err(()); | ||
| 110 | // } | ||
| 111 | |||
| 112 | // core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len); | ||
| 113 | |||
| 114 | // Ok(len) | ||
| 115 | // } else { | ||
| 116 | // let evt_data: *const EvtPacket = self.ptr.cast(); | ||
| 117 | // let evt_serial: *const EvtSerial = &(*evt_data).evt_serial; | ||
| 118 | // let evt_serial_buf: *const u8 = evt_serial.cast(); | ||
| 119 | |||
| 120 | // let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE; | ||
| 121 | // if len > buf.len() { | ||
| 122 | // return Err(()); | ||
| 123 | // } | ||
| 124 | |||
| 125 | // core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len); | ||
| 126 | |||
| 127 | // Ok(len) | ||
| 128 | // } | ||
| 129 | // } | ||
| 130 | |||
| 131 | unsafe { | ||
| 132 | let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?; | ||
| 133 | |||
| 134 | let evt_data: *const EvtPacket = self.ptr.cast(); | ||
| 135 | let evt_serial: *const EvtSerial = &(*evt_data).evt_serial; | ||
| 136 | let evt_serial_buf: *const u8 = evt_serial.cast(); | ||
| 137 | |||
| 138 | let acl_data: *const AclDataPacket = self.ptr.cast(); | ||
| 139 | let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial; | ||
| 140 | let acl_serial_buf: *const u8 = acl_serial.cast(); | ||
| 141 | |||
| 142 | if let TlPacketType::AclData = evt_kind { | ||
| 143 | let len = (*acl_serial).length as usize + 5; | ||
| 144 | if len > buf.len() { | ||
| 145 | return Err(()); | ||
| 146 | } | ||
| 147 | |||
| 148 | core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len); | ||
| 149 | |||
| 150 | Ok(len) | ||
| 151 | } else { | ||
| 152 | let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE; | ||
| 153 | if len > buf.len() { | ||
| 154 | return Err(()); | ||
| 155 | } | ||
| 156 | |||
| 157 | core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len); | ||
| 158 | |||
| 159 | Ok(len) | ||
| 160 | } | ||
| 161 | } | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | impl Drop for EvtBox { | ||
| 166 | fn drop(&mut self) { | ||
| 167 | use crate::ipcc::IpccExt; | ||
| 168 | let mut ipcc = unsafe { crate::Peripherals::steal() }.IPCC.constrain(); | ||
| 169 | mm::MemoryManager::evt_drop(self.ptr, &mut ipcc); | ||
| 170 | } | ||
| 171 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/mm.rs b/embassy-stm32/src/tl_mbox/mm.rs index cf4797305..588b32919 100644 --- a/embassy-stm32/src/tl_mbox/mm.rs +++ b/embassy-stm32/src/tl_mbox/mm.rs | |||
| @@ -1,10 +1,12 @@ | |||
| 1 | use core::mem::MaybeUninit; | 1 | use core::mem::MaybeUninit; |
| 2 | 2 | ||
| 3 | use super::unsafe_linked_list::LST_init_head; | 3 | use super::evt::EvtPacket; |
| 4 | use super::unsafe_linked_list::{LST_init_head, LST_insert_tail, LST_is_empty, LST_remove_head}; | ||
| 4 | use super::{ | 5 | use super::{ |
| 5 | MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, SYS_SPARE_EVT_BUF, | 6 | channels, MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, |
| 6 | TL_MEM_MANAGER_TABLE, | 7 | SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE, TL_REF_TABLE, |
| 7 | }; | 8 | }; |
| 9 | use crate::ipcc::Ipcc; | ||
| 8 | 10 | ||
| 9 | pub struct MemoryManager; | 11 | pub struct MemoryManager; |
| 10 | 12 | ||
| @@ -27,4 +29,43 @@ impl MemoryManager { | |||
| 27 | 29 | ||
| 28 | MemoryManager | 30 | MemoryManager |
| 29 | } | 31 | } |
| 32 | |||
| 33 | pub fn evt_handler(ipcc: &mut Ipcc) { | ||
| 34 | ipcc.c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false); | ||
| 35 | Self::send_free_buf(); | ||
| 36 | ipcc.c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL); | ||
| 37 | } | ||
| 38 | |||
| 39 | pub fn evt_drop(evt: *mut EvtPacket, ipcc: &mut Ipcc) { | ||
| 40 | unsafe { | ||
| 41 | let list_node = evt.cast(); | ||
| 42 | |||
| 43 | LST_insert_tail(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), list_node); | ||
| 44 | } | ||
| 45 | |||
| 46 | let channel_is_busy = ipcc.c1_is_active_flag(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL); | ||
| 47 | |||
| 48 | // postpone event buffer freeing to IPCC interrupt handler | ||
| 49 | if channel_is_busy { | ||
| 50 | ipcc.c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, true); | ||
| 51 | } else { | ||
| 52 | Self::send_free_buf(); | ||
| 53 | ipcc.c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | fn send_free_buf() { | ||
| 58 | unsafe { | ||
| 59 | let mut node_ptr = core::ptr::null_mut(); | ||
| 60 | let node_ptr_ptr: *mut _ = &mut node_ptr; | ||
| 61 | |||
| 62 | while !LST_is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) { | ||
| 63 | LST_remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), node_ptr_ptr); | ||
| 64 | LST_insert_tail( | ||
| 65 | (*(*TL_REF_TABLE.as_ptr()).mem_manager_table).pevt_free_buffer_queue, | ||
| 66 | node_ptr, | ||
| 67 | ); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 30 | } | 71 | } |
diff --git a/embassy-stm32/src/tl_mbox/mod.rs b/embassy-stm32/src/tl_mbox/mod.rs index 0cee26b74..3651b8ea5 100644 --- a/embassy-stm32/src/tl_mbox/mod.rs +++ b/embassy-stm32/src/tl_mbox/mod.rs | |||
| @@ -1,20 +1,27 @@ | |||
| 1 | use core::mem::MaybeUninit; | 1 | use core::mem::MaybeUninit; |
| 2 | 2 | ||
| 3 | use bit_field::BitField; | 3 | use bit_field::BitField; |
| 4 | use embassy_cortex_m::interrupt::InterruptExt; | ||
| 5 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 6 | use embassy_sync::channel::Channel; | ||
| 4 | 7 | ||
| 5 | use self::ble::Ble; | 8 | use self::ble::Ble; |
| 6 | use self::cmd::{AclDataPacket, CmdPacket}; | 9 | use self::cmd::{AclDataPacket, CmdPacket}; |
| 7 | use self::evt::CsEvt; | 10 | use self::evt::{CsEvt, EvtBox}; |
| 8 | use self::mm::MemoryManager; | 11 | use self::mm::MemoryManager; |
| 12 | use self::shci::{shci_ble_init, ShciBleInitCmdParam}; | ||
| 9 | use self::sys::Sys; | 13 | use self::sys::Sys; |
| 10 | use self::unsafe_linked_list::LinkedListNode; | 14 | use self::unsafe_linked_list::LinkedListNode; |
| 15 | use crate::_generated::interrupt::{IPCC_C1_RX, IPCC_C1_TX}; | ||
| 11 | use crate::ipcc::Ipcc; | 16 | use crate::ipcc::Ipcc; |
| 12 | 17 | ||
| 13 | mod ble; | 18 | mod ble; |
| 14 | mod channels; | 19 | mod channels; |
| 15 | mod cmd; | 20 | mod cmd; |
| 21 | mod consts; | ||
| 16 | mod evt; | 22 | mod evt; |
| 17 | mod mm; | 23 | mod mm; |
| 24 | mod shci; | ||
| 18 | mod sys; | 25 | mod sys; |
| 19 | mod unsafe_linked_list; | 26 | mod unsafe_linked_list; |
| 20 | 27 | ||
| @@ -236,18 +243,14 @@ static mut FREE_BUFF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | |||
| 236 | // not in shared RAM | 243 | // not in shared RAM |
| 237 | static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | 244 | static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); |
| 238 | 245 | ||
| 239 | #[allow(dead_code)] // Not used currently but reserved | ||
| 240 | #[link_section = "MB_MEM1"] | ||
| 241 | static mut TRACES_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 242 | |||
| 243 | #[link_section = "MB_MEM2"] | 246 | #[link_section = "MB_MEM2"] |
| 244 | static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> = | 247 | static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> = |
| 245 | MaybeUninit::uninit(); | 248 | MaybeUninit::uninit(); |
| 246 | 249 | ||
| 247 | #[link_section = "MB_MEM1"] | 250 | #[link_section = "MB_MEM2"] |
| 248 | static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | 251 | static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); |
| 249 | 252 | ||
| 250 | #[link_section = "MB_MEM1"] | 253 | #[link_section = "MB_MEM2"] |
| 251 | static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | 254 | static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); |
| 252 | 255 | ||
| 253 | #[link_section = "MB_MEM2"] | 256 | #[link_section = "MB_MEM2"] |
| @@ -271,6 +274,9 @@ static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit(); | |||
| 271 | // "magic" numbers from ST ---v---v | 274 | // "magic" numbers from ST ---v---v |
| 272 | static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit(); | 275 | static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit(); |
| 273 | 276 | ||
| 277 | // TODO: get a better size, this is a placeholder | ||
| 278 | pub(crate) static TL_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 5> = Channel::new(); | ||
| 279 | |||
| 274 | pub struct TlMbox { | 280 | pub struct TlMbox { |
| 275 | _sys: Sys, | 281 | _sys: Sys, |
| 276 | _ble: Ble, | 282 | _ble: Ble, |
| @@ -279,7 +285,7 @@ pub struct TlMbox { | |||
| 279 | 285 | ||
| 280 | impl TlMbox { | 286 | impl TlMbox { |
| 281 | /// initializes low-level transport between CPU1 and BLE stack on CPU2 | 287 | /// initializes low-level transport between CPU1 and BLE stack on CPU2 |
| 282 | pub fn init(ipcc: &mut Ipcc) -> TlMbox { | 288 | pub fn init(ipcc: &mut Ipcc, rx_irq: IPCC_C1_RX, tx_irq: IPCC_C1_TX) -> TlMbox { |
| 283 | unsafe { | 289 | unsafe { |
| 284 | TL_REF_TABLE = MaybeUninit::new(RefTable { | 290 | TL_REF_TABLE = MaybeUninit::new(RefTable { |
| 285 | device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(), | 291 | device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(), |
| @@ -320,6 +326,24 @@ impl TlMbox { | |||
| 320 | let _ble = Ble::new(ipcc); | 326 | let _ble = Ble::new(ipcc); |
| 321 | let _mm = MemoryManager::new(); | 327 | let _mm = MemoryManager::new(); |
| 322 | 328 | ||
| 329 | rx_irq.disable(); | ||
| 330 | tx_irq.disable(); | ||
| 331 | |||
| 332 | rx_irq.set_handler_context(ipcc.as_mut_ptr() as *mut ()); | ||
| 333 | tx_irq.set_handler_context(ipcc.as_mut_ptr() as *mut ()); | ||
| 334 | |||
| 335 | rx_irq.set_handler(|ipcc| { | ||
| 336 | let ipcc: &mut Ipcc = unsafe { &mut *ipcc.cast() }; | ||
| 337 | Self::interrupt_ipcc_rx_handler(ipcc); | ||
| 338 | }); | ||
| 339 | tx_irq.set_handler(|ipcc| { | ||
| 340 | let ipcc: &mut Ipcc = unsafe { &mut *ipcc.cast() }; | ||
| 341 | Self::interrupt_ipcc_tx_handler(ipcc); | ||
| 342 | }); | ||
| 343 | |||
| 344 | rx_irq.enable(); | ||
| 345 | tx_irq.enable(); | ||
| 346 | |||
| 323 | TlMbox { _sys, _ble, _mm } | 347 | TlMbox { _sys, _ble, _mm } |
| 324 | } | 348 | } |
| 325 | 349 | ||
| @@ -333,4 +357,41 @@ impl TlMbox { | |||
| 333 | None | 357 | None |
| 334 | } | 358 | } |
| 335 | } | 359 | } |
| 360 | |||
| 361 | pub fn shci_ble_init(&self, ipcc: &mut Ipcc, param: ShciBleInitCmdParam) { | ||
| 362 | shci_ble_init(ipcc, param); | ||
| 363 | } | ||
| 364 | |||
| 365 | pub fn send_ble_cmd(&self, ipcc: &mut Ipcc, buf: &[u8]) { | ||
| 366 | ble::Ble::send_cmd(ipcc, buf); | ||
| 367 | } | ||
| 368 | |||
| 369 | // pub fn send_sys_cmd(&self, ipcc: &mut Ipcc, buf: &[u8]) { | ||
| 370 | // sys::Sys::send_cmd(ipcc, buf); | ||
| 371 | // } | ||
| 372 | |||
| 373 | pub async fn read(&self) -> EvtBox { | ||
| 374 | TL_CHANNEL.recv().await | ||
| 375 | } | ||
| 376 | |||
| 377 | fn interrupt_ipcc_rx_handler(ipcc: &mut Ipcc) { | ||
| 378 | if ipcc.is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) { | ||
| 379 | sys::Sys::evt_handler(ipcc); | ||
| 380 | } else if ipcc.is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) { | ||
| 381 | ble::Ble::evt_handler(ipcc); | ||
| 382 | } else { | ||
| 383 | todo!() | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | fn interrupt_ipcc_tx_handler(ipcc: &mut Ipcc) { | ||
| 388 | if ipcc.is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) { | ||
| 389 | // TODO: handle this case | ||
| 390 | let _ = sys::Sys::cmd_evt_handler(ipcc); | ||
| 391 | } else if ipcc.is_tx_pending(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL) { | ||
| 392 | mm::MemoryManager::evt_handler(ipcc); | ||
| 393 | } else { | ||
| 394 | todo!() | ||
| 395 | } | ||
| 396 | } | ||
| 336 | } | 397 | } |
diff --git a/embassy-stm32/src/tl_mbox/shci.rs b/embassy-stm32/src/tl_mbox/shci.rs new file mode 100644 index 000000000..7f224cb1a --- /dev/null +++ b/embassy-stm32/src/tl_mbox/shci.rs | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | //! HCI commands for system channel | ||
| 2 | |||
| 3 | use super::cmd::CmdPacket; | ||
| 4 | use super::consts::TlPacketType; | ||
| 5 | use super::{channels, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE, TL_SYS_TABLE}; | ||
| 6 | use crate::ipcc::Ipcc; | ||
| 7 | |||
| 8 | const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66; | ||
| 9 | pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE; | ||
| 10 | #[allow(dead_code)] | ||
| 11 | const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE; | ||
| 12 | |||
| 13 | #[derive(Clone, Copy)] | ||
| 14 | #[repr(C, packed)] | ||
| 15 | pub struct ShciBleInitCmdParam { | ||
| 16 | /// NOT USED CURRENTLY | ||
| 17 | pub p_ble_buffer_address: u32, | ||
| 18 | |||
| 19 | /// Size of the Buffer allocated in pBleBufferAddress | ||
| 20 | pub ble_buffer_size: u32, | ||
| 21 | |||
| 22 | pub num_attr_record: u16, | ||
| 23 | pub num_attr_serv: u16, | ||
| 24 | pub attr_value_arr_size: u16, | ||
| 25 | pub num_of_links: u8, | ||
| 26 | pub extended_packet_length_enable: u8, | ||
| 27 | pub pr_write_list_size: u8, | ||
| 28 | pub mb_lock_count: u8, | ||
| 29 | |||
| 30 | pub att_mtu: u16, | ||
| 31 | pub slave_sca: u16, | ||
| 32 | pub master_sca: u8, | ||
| 33 | pub ls_source: u8, | ||
| 34 | pub max_conn_event_length: u32, | ||
| 35 | pub hs_startup_time: u16, | ||
| 36 | pub viterbi_enable: u8, | ||
| 37 | pub ll_only: u8, | ||
| 38 | pub hw_version: u8, | ||
| 39 | } | ||
| 40 | |||
| 41 | impl Default for ShciBleInitCmdParam { | ||
| 42 | fn default() -> Self { | ||
| 43 | Self { | ||
| 44 | p_ble_buffer_address: 0, | ||
| 45 | ble_buffer_size: 0, | ||
| 46 | num_attr_record: 68, | ||
| 47 | num_attr_serv: 8, | ||
| 48 | attr_value_arr_size: 1344, | ||
| 49 | num_of_links: 2, | ||
| 50 | extended_packet_length_enable: 1, | ||
| 51 | pr_write_list_size: 0x3A, | ||
| 52 | mb_lock_count: 0x79, | ||
| 53 | att_mtu: 156, | ||
| 54 | slave_sca: 500, | ||
| 55 | master_sca: 0, | ||
| 56 | ls_source: 1, | ||
| 57 | max_conn_event_length: 0xFFFFFFFF, | ||
| 58 | hs_startup_time: 0x148, | ||
| 59 | viterbi_enable: 1, | ||
| 60 | ll_only: 0, | ||
| 61 | hw_version: 0, | ||
| 62 | } | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | #[derive(Clone, Copy, Default)] | ||
| 67 | #[repr(C, packed)] | ||
| 68 | pub struct ShciHeader { | ||
| 69 | metadata: [u32; 3], | ||
| 70 | } | ||
| 71 | |||
| 72 | #[derive(Clone, Copy)] | ||
| 73 | #[repr(C, packed)] | ||
| 74 | pub struct ShciBleInitCmdPacket { | ||
| 75 | header: ShciHeader, | ||
| 76 | param: ShciBleInitCmdParam, | ||
| 77 | } | ||
| 78 | |||
| 79 | pub fn shci_ble_init(ipcc: &mut Ipcc, param: ShciBleInitCmdParam) { | ||
| 80 | let mut packet = ShciBleInitCmdPacket { | ||
| 81 | header: ShciHeader::default(), | ||
| 82 | param, | ||
| 83 | }; | ||
| 84 | |||
| 85 | let packet_ptr: *mut ShciBleInitCmdPacket = &mut packet; | ||
| 86 | |||
| 87 | unsafe { | ||
| 88 | let cmd_ptr: *mut CmdPacket = packet_ptr.cast(); | ||
| 89 | |||
| 90 | (*cmd_ptr).cmd_serial.cmd.cmd_code = SCHI_OPCODE_BLE_INIT; | ||
| 91 | (*cmd_ptr).cmd_serial.cmd.payload_len = core::mem::size_of::<ShciBleInitCmdParam>() as u8; | ||
| 92 | |||
| 93 | let mut cmd_buf = &mut *(*TL_SYS_TABLE.as_mut_ptr()).pcmd_buffer; | ||
| 94 | core::ptr::write(cmd_buf, *cmd_ptr); | ||
| 95 | |||
| 96 | cmd_buf.cmd_serial.ty = TlPacketType::SysCmd as u8; | ||
| 97 | |||
| 98 | ipcc.c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL); | ||
| 99 | ipcc.c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true); | ||
| 100 | } | ||
| 101 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/sys.rs b/embassy-stm32/src/tl_mbox/sys.rs index 13ae7f9f9..122657550 100644 --- a/embassy-stm32/src/tl_mbox/sys.rs +++ b/embassy-stm32/src/tl_mbox/sys.rs | |||
| @@ -1,13 +1,18 @@ | |||
| 1 | use core::mem::MaybeUninit; | 1 | use core::mem::MaybeUninit; |
| 2 | 2 | ||
| 3 | use super::unsafe_linked_list::LST_init_head; | 3 | use embassy_futures::block_on; |
| 4 | use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_SYS_TABLE}; | 4 | |
| 5 | use super::cmd::{CmdPacket, CmdSerial}; | ||
| 6 | use super::consts::TlPacketType; | ||
| 7 | use super::evt::{CcEvt, EvtBox, EvtSerial}; | ||
| 8 | use super::unsafe_linked_list::{LST_init_head, LST_is_empty, LST_remove_head}; | ||
| 9 | use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_CHANNEL, TL_REF_TABLE, TL_SYS_TABLE}; | ||
| 5 | use crate::ipcc::Ipcc; | 10 | use crate::ipcc::Ipcc; |
| 6 | 11 | ||
| 7 | pub struct Sys; | 12 | pub struct Sys; |
| 8 | 13 | ||
| 9 | impl Sys { | 14 | impl Sys { |
| 10 | pub fn new(ipcc: &mut Ipcc) -> Self { | 15 | pub(crate) fn new(ipcc: &mut Ipcc) -> Self { |
| 11 | unsafe { | 16 | unsafe { |
| 12 | LST_init_head(SYSTEM_EVT_QUEUE.as_mut_ptr()); | 17 | LST_init_head(SYSTEM_EVT_QUEUE.as_mut_ptr()); |
| 13 | 18 | ||
| @@ -21,4 +26,62 @@ impl Sys { | |||
| 21 | 26 | ||
| 22 | Sys | 27 | Sys |
| 23 | } | 28 | } |
| 29 | |||
| 30 | pub(crate) fn evt_handler(ipcc: &mut Ipcc) { | ||
| 31 | unsafe { | ||
| 32 | let mut node_ptr = core::ptr::null_mut(); | ||
| 33 | let node_ptr_ptr: *mut _ = &mut node_ptr; | ||
| 34 | |||
| 35 | while !LST_is_empty(SYSTEM_EVT_QUEUE.as_mut_ptr()) { | ||
| 36 | LST_remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr(), node_ptr_ptr); | ||
| 37 | |||
| 38 | let event = node_ptr.cast(); | ||
| 39 | let event = EvtBox::new(event); | ||
| 40 | |||
| 41 | // TODO: not really happy about this | ||
| 42 | block_on(TL_CHANNEL.send(event)); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | ipcc.c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL); | ||
| 47 | } | ||
| 48 | |||
| 49 | pub(crate) fn cmd_evt_handler(ipcc: &mut Ipcc) -> CcEvt { | ||
| 50 | ipcc.c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false); | ||
| 51 | |||
| 52 | // ST's command response data structure is really convoluted. | ||
| 53 | // | ||
| 54 | // for command response events on SYS channel, the header is missing | ||
| 55 | // and one should: | ||
| 56 | // 1. interpret the content of CMD_BUFFER as CmdPacket | ||
| 57 | // 2. Access CmdPacket's cmdserial field and interpret its content as EvtSerial | ||
| 58 | // 3. Access EvtSerial's evt field (as Evt) and interpret its payload as CcEvt | ||
| 59 | // 4. CcEvt type is the actual SHCI response | ||
| 60 | // 5. profit | ||
| 61 | unsafe { | ||
| 62 | let cmd: *const CmdPacket = (*TL_SYS_TABLE.as_ptr()).pcmd_buffer; | ||
| 63 | let cmd_serial: *const CmdSerial = &(*cmd).cmd_serial; | ||
| 64 | let evt_serial: *const EvtSerial = cmd_serial.cast(); | ||
| 65 | let cc = (*evt_serial).evt.payload.as_ptr().cast(); | ||
| 66 | *cc | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | #[allow(dead_code)] | ||
| 71 | pub(crate) fn send_cmd(ipcc: &mut Ipcc, buf: &[u8]) { | ||
| 72 | unsafe { | ||
| 73 | // TODO: check this | ||
| 74 | let cmd_buffer = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer; | ||
| 75 | let cmd_serial: *mut CmdSerial = &mut (*cmd_buffer).cmd_serial; | ||
| 76 | let cmd_serial_buf = cmd_serial.cast(); | ||
| 77 | |||
| 78 | core::ptr::copy(buf.as_ptr(), cmd_serial_buf, buf.len()); | ||
| 79 | |||
| 80 | let mut cmd_packet = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer; | ||
| 81 | cmd_packet.cmd_serial.ty = TlPacketType::SysCmd as u8; | ||
| 82 | |||
| 83 | ipcc.c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL); | ||
| 84 | ipcc.c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true); | ||
| 85 | } | ||
| 86 | } | ||
| 24 | } | 87 | } |
diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs index 6876526ae..ccd01cbc7 100644 --- a/examples/stm32wb/src/bin/tl_mbox.rs +++ b/examples/stm32wb/src/bin/tl_mbox.rs | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::interrupt; | ||
| 7 | use embassy_stm32::ipcc::{Config, Ipcc}; | 8 | use embassy_stm32::ipcc::{Config, Ipcc}; |
| 8 | use embassy_stm32::tl_mbox::TlMbox; | 9 | use embassy_stm32::tl_mbox::TlMbox; |
| 9 | use embassy_time::{Duration, Timer}; | 10 | use embassy_time::{Duration, Timer}; |
| @@ -40,7 +41,10 @@ async fn main(_spawner: Spawner) { | |||
| 40 | let config = Config::default(); | 41 | let config = Config::default(); |
| 41 | let mut ipcc = Ipcc::new(p.IPCC, config); | 42 | let mut ipcc = Ipcc::new(p.IPCC, config); |
| 42 | 43 | ||
| 43 | let mbox = TlMbox::init(&mut ipcc); | 44 | let rx_irq = interrupt::take!(IPCC_C1_RX); |
| 45 | let tx_irq = interrupt::take!(IPCC_C1_TX); | ||
| 46 | |||
| 47 | let mbox = TlMbox::init(&mut ipcc, rx_irq, tx_irq); | ||
| 44 | 48 | ||
| 45 | loop { | 49 | loop { |
| 46 | let wireless_fw_info = mbox.wireless_fw_info(); | 50 | let wireless_fw_info = mbox.wireless_fw_info(); |
diff --git a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs b/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs new file mode 100644 index 000000000..315172df8 --- /dev/null +++ b/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::interrupt; | ||
| 8 | use embassy_stm32::ipcc::{Config, Ipcc}; | ||
| 9 | use embassy_stm32::tl_mbox::TlMbox; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | /* | ||
| 15 | How to make this work: | ||
| 16 | |||
| 17 | - Obtain a NUCLEO-STM32WB55 from your preferred supplier. | ||
| 18 | - Download and Install STM32CubeProgrammer. | ||
| 19 | - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from | ||
| 20 | gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x | ||
| 21 | - Open STM32CubeProgrammer | ||
| 22 | - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware. | ||
| 23 | - Once complete, click connect to connect to the device. | ||
| 24 | - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services". | ||
| 25 | - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file | ||
| 26 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". | ||
| 27 | - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the | ||
| 28 | stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address. | ||
| 29 | - Select that file, the memory address, "verify download", and then "Firmware Upgrade". | ||
| 30 | - Disconnect from the device. | ||
| 31 | - In the examples folder for stm32wb, modify the memory.x file to match your target device. | ||
| 32 | - Run this example. | ||
| 33 | |||
| 34 | Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. | ||
| 35 | */ | ||
| 36 | |||
| 37 | let p = embassy_stm32::init(Default::default()); | ||
| 38 | info!("Hello World!"); | ||
| 39 | |||
| 40 | let config = Config::default(); | ||
| 41 | let mut ipcc = Ipcc::new(p.IPCC, config); | ||
| 42 | |||
| 43 | let rx_irq = interrupt::take!(IPCC_C1_RX); | ||
| 44 | let tx_irq = interrupt::take!(IPCC_C1_TX); | ||
| 45 | |||
| 46 | let mbox = TlMbox::init(&mut ipcc, rx_irq, tx_irq); | ||
| 47 | |||
| 48 | // initialize ble stack, does not return a response | ||
| 49 | // mbox.shci_ble_init(&mut ipcc, Default::default()); | ||
| 50 | |||
| 51 | info!("waiting for coprocessor to boot"); | ||
| 52 | let event_box = mbox.read().await; | ||
| 53 | |||
| 54 | let mut payload = [0u8; 6]; | ||
| 55 | event_box.copy_into_slice(&mut payload).unwrap(); | ||
| 56 | |||
| 57 | let event_packet = event_box.evt(); | ||
| 58 | let kind = event_packet.evt_serial.kind; | ||
| 59 | |||
| 60 | // means recieved SYS event, which indicates in this case that the coprocessor is ready | ||
| 61 | if kind == 0x12 { | ||
| 62 | let code = event_packet.evt_serial.evt.evt_code; | ||
| 63 | let payload_len = event_packet.evt_serial.evt.payload_len; | ||
| 64 | |||
| 65 | info!( | ||
| 66 | "==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}", | ||
| 67 | kind, | ||
| 68 | code, | ||
| 69 | payload_len, | ||
| 70 | payload[3..] | ||
| 71 | ); | ||
| 72 | } | ||
| 73 | |||
| 74 | mbox.shci_ble_init(&mut ipcc, Default::default()); | ||
| 75 | |||
| 76 | info!("resetting BLE"); | ||
| 77 | mbox.send_ble_cmd(&mut ipcc, &[0x01, 0x03, 0x0c]); | ||
| 78 | |||
| 79 | let event_box = mbox.read().await; | ||
| 80 | |||
| 81 | let mut payload = [0u8; 7]; | ||
| 82 | event_box.copy_into_slice(&mut payload).unwrap(); | ||
| 83 | |||
| 84 | let event_packet = event_box.evt(); | ||
| 85 | let kind = event_packet.evt_serial.kind; | ||
| 86 | |||
| 87 | let code = event_packet.evt_serial.evt.evt_code; | ||
| 88 | let payload_len = event_packet.evt_serial.evt.payload_len; | ||
| 89 | |||
| 90 | info!( | ||
| 91 | "==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}", | ||
| 92 | kind, code, payload_len, payload | ||
| 93 | ); | ||
| 94 | |||
| 95 | loop {} | ||
| 96 | } | ||
