aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgoueslati <[email protected]>2023-05-15 10:25:02 +0100
committergoueslati <[email protected]>2023-05-15 10:25:02 +0100
commitd97724cca3164250118c732759f403f4f94d4629 (patch)
tree10a69d2f4fd843a08b3c75fa94afc223087d6350
parent3810fe6a2058d04054c7242216a7bc9d2993667b (diff)
tl_mbox read and write
-rw-r--r--embassy-stm32/src/ipcc.rs15
-rw-r--r--embassy-stm32/src/tl_mbox/ble.rs48
-rw-r--r--embassy-stm32/src/tl_mbox/channels.rs8
-rw-r--r--embassy-stm32/src/tl_mbox/consts.rs53
-rw-r--r--embassy-stm32/src/tl_mbox/evt.rs163
-rw-r--r--embassy-stm32/src/tl_mbox/mm.rs47
-rw-r--r--embassy-stm32/src/tl_mbox/mod.rs77
-rw-r--r--embassy-stm32/src/tl_mbox/shci.rs101
-rw-r--r--embassy-stm32/src/tl_mbox/sys.rs69
-rw-r--r--examples/stm32wb/src/bin/tl_mbox.rs6
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_tx_rx.rs96
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
163impl sealed::Instance for crate::peripherals::IPCC { 167impl 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
186pub trait IpccExt<'d> {
187 fn constrain(self) -> Ipcc<'d>;
188}
189impl<'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 @@
1use core::mem::MaybeUninit; 1use core::mem::MaybeUninit;
2 2
3use super::unsafe_linked_list::LST_init_head; 3use embassy_futures::block_on;
4use super::{channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE}; 4
5use super::cmd::CmdSerial;
6use super::consts::TlPacketType;
7use super::evt::EvtBox;
8use super::unsafe_linked_list::{LST_init_head, LST_is_empty, LST_remove_head};
9use 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};
5use crate::ipcc::Ipcc; 13use crate::ipcc::Ipcc;
14use crate::tl_mbox::cmd::CmdPacket;
6 15
7pub struct Ble; 16pub struct Ble;
8 17
9impl Ble { 18impl 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 @@
52pub mod cpu1 { 52pub 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)]
3pub 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
27impl 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 @@
1use core::mem::MaybeUninit;
2
3use super::cmd::{AclDataPacket, AclDataSerial};
4use super::consts::TlPacketType;
5use super::{PacketHeader, TL_EVT_HEADER_SIZE};
6use 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)]
20pub 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)]
28pub 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)]
36pub 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)]
51pub 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
57pub struct EvtBox {
58 ptr: *mut EvtPacket,
59}
60
61unsafe impl Send for EvtBox {}
62impl 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
165impl 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 @@
1use core::mem::MaybeUninit; 1use core::mem::MaybeUninit;
2 2
3use super::unsafe_linked_list::LST_init_head; 3use super::evt::EvtPacket;
4use super::unsafe_linked_list::{LST_init_head, LST_insert_tail, LST_is_empty, LST_remove_head};
4use super::{ 5use 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};
9use crate::ipcc::Ipcc;
8 10
9pub struct MemoryManager; 11pub 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 @@
1use core::mem::MaybeUninit; 1use core::mem::MaybeUninit;
2 2
3use bit_field::BitField; 3use bit_field::BitField;
4use embassy_cortex_m::interrupt::InterruptExt;
5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
6use embassy_sync::channel::Channel;
4 7
5use self::ble::Ble; 8use self::ble::Ble;
6use self::cmd::{AclDataPacket, CmdPacket}; 9use self::cmd::{AclDataPacket, CmdPacket};
7use self::evt::CsEvt; 10use self::evt::{CsEvt, EvtBox};
8use self::mm::MemoryManager; 11use self::mm::MemoryManager;
12use self::shci::{shci_ble_init, ShciBleInitCmdParam};
9use self::sys::Sys; 13use self::sys::Sys;
10use self::unsafe_linked_list::LinkedListNode; 14use self::unsafe_linked_list::LinkedListNode;
15use crate::_generated::interrupt::{IPCC_C1_RX, IPCC_C1_TX};
11use crate::ipcc::Ipcc; 16use crate::ipcc::Ipcc;
12 17
13mod ble; 18mod ble;
14mod channels; 19mod channels;
15mod cmd; 20mod cmd;
21mod consts;
16mod evt; 22mod evt;
17mod mm; 23mod mm;
24mod shci;
18mod sys; 25mod sys;
19mod unsafe_linked_list; 26mod 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
237static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); 244static 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"]
241static mut TRACES_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
242
243#[link_section = "MB_MEM2"] 246#[link_section = "MB_MEM2"]
244static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> = 247static 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"]
248static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); 251static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
249 252
250#[link_section = "MB_MEM1"] 253#[link_section = "MB_MEM2"]
251static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); 254static 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
272static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit(); 275static 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
278pub(crate) static TL_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 5> = Channel::new();
279
274pub struct TlMbox { 280pub struct TlMbox {
275 _sys: Sys, 281 _sys: Sys,
276 _ble: Ble, 282 _ble: Ble,
@@ -279,7 +285,7 @@ pub struct TlMbox {
279 285
280impl TlMbox { 286impl 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
3use super::cmd::CmdPacket;
4use super::consts::TlPacketType;
5use super::{channels, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE, TL_SYS_TABLE};
6use crate::ipcc::Ipcc;
7
8const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66;
9pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
10#[allow(dead_code)]
11const 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)]
15pub 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
41impl 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)]
68pub struct ShciHeader {
69 metadata: [u32; 3],
70}
71
72#[derive(Clone, Copy)]
73#[repr(C, packed)]
74pub struct ShciBleInitCmdPacket {
75 header: ShciHeader,
76 param: ShciBleInitCmdParam,
77}
78
79pub 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 @@
1use core::mem::MaybeUninit; 1use core::mem::MaybeUninit;
2 2
3use super::unsafe_linked_list::LST_init_head; 3use embassy_futures::block_on;
4use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_SYS_TABLE}; 4
5use super::cmd::{CmdPacket, CmdSerial};
6use super::consts::TlPacketType;
7use super::evt::{CcEvt, EvtBox, EvtSerial};
8use super::unsafe_linked_list::{LST_init_head, LST_is_empty, LST_remove_head};
9use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_CHANNEL, TL_REF_TABLE, TL_SYS_TABLE};
5use crate::ipcc::Ipcc; 10use crate::ipcc::Ipcc;
6 11
7pub struct Sys; 12pub struct Sys;
8 13
9impl Sys { 14impl 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
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::interrupt;
7use embassy_stm32::ipcc::{Config, Ipcc}; 8use embassy_stm32::ipcc::{Config, Ipcc};
8use embassy_stm32::tl_mbox::TlMbox; 9use embassy_stm32::tl_mbox::TlMbox;
9use embassy_time::{Duration, Timer}; 10use 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
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::interrupt;
8use embassy_stm32::ipcc::{Config, Ipcc};
9use embassy_stm32::tl_mbox::TlMbox;
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async 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}