aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-06-12 20:26:38 -0500
committerxoviat <[email protected]>2023-06-12 20:26:38 -0500
commit7f63fbbf4a7acf258198010930a6b45435fc0e57 (patch)
tree8b11dd462938caf0fafd08386da8e901eaee757e
parentc822fd46e558fc694bbec3358f31076e89d99164 (diff)
parentbf32dc5d3acee1f73fe445976bde474ffa6d04e0 (diff)
Merge branch 'old_tl_mbox' of github.com:OueslatiGhaith/embassy into old-tl-mbox
-rw-r--r--embassy-stm32-wpan/Cargo.toml39
-rw-r--r--embassy-stm32-wpan/build.rs34
-rw-r--r--embassy-stm32-wpan/src/ble.rs (renamed from embassy-stm32/src/tl_mbox/ble.rs)56
-rw-r--r--embassy-stm32-wpan/src/channels.rs (renamed from embassy-stm32/src/tl_mbox/channels.rs)16
-rw-r--r--embassy-stm32-wpan/src/cmd.rs77
-rw-r--r--embassy-stm32-wpan/src/consts.rs (renamed from embassy-stm32/src/tl_mbox/consts.rs)4
-rw-r--r--embassy-stm32-wpan/src/evt.rs (renamed from embassy-stm32/src/tl_mbox/evt.rs)106
-rw-r--r--embassy-stm32-wpan/src/fmt.rs225
-rw-r--r--embassy-stm32-wpan/src/lib.rs266
-rw-r--r--embassy-stm32-wpan/src/mm.rs75
-rw-r--r--embassy-stm32-wpan/src/rc.rs50
-rw-r--r--embassy-stm32-wpan/src/shci.rs (renamed from embassy-stm32/src/tl_mbox/shci.rs)35
-rw-r--r--embassy-stm32-wpan/src/sys.rs (renamed from embassy-stm32/src/tl_mbox/sys.rs)71
-rw-r--r--embassy-stm32-wpan/src/tables.rs175
-rw-r--r--embassy-stm32-wpan/src/unsafe_linked_list.rs (renamed from embassy-stm32/src/tl_mbox/unsafe_linked_list.rs)9
-rw-r--r--embassy-stm32/src/ipcc.rs (renamed from embassy-stm32/src/tl_mbox/ipcc.rs)60
-rw-r--r--embassy-stm32/src/lib.rs4
-rw-r--r--embassy-stm32/src/tl_mbox/cmd.rs49
-rw-r--r--embassy-stm32/src/tl_mbox/mm.rs67
-rw-r--r--embassy-stm32/src/tl_mbox/mod.rs417
-rw-r--r--examples/stm32wb/Cargo.toml1
-rw-r--r--examples/stm32wb/src/bin/tl_mbox.rs11
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_tx_rx.rs63
-rw-r--r--tests/stm32/Cargo.toml3
-rw-r--r--tests/stm32/src/bin/tl_mbox.rs11
25 files changed, 1200 insertions, 724 deletions
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
new file mode 100644
index 000000000..058d0e29f
--- /dev/null
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -0,0 +1,39 @@
1[package]
2name = "embassy-stm32-wpan"
3version = "0.1.0"
4edition = "2021"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
9embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
10embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
11embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
12embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" }
13embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
14
15defmt = { version = "0.3", optional = true }
16cortex-m = "0.7.6"
17heapless = "0.7.16"
18
19bit_field = "0.10.2"
20
21[features]
22defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"]
23
24stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
25stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]
26stm32wb30ce = [ "embassy-stm32/stm32wb30ce" ]
27stm32wb35cc = [ "embassy-stm32/stm32wb35cc" ]
28stm32wb35ce = [ "embassy-stm32/stm32wb35ce" ]
29stm32wb50cg = [ "embassy-stm32/stm32wb50cg" ]
30stm32wb55cc = [ "embassy-stm32/stm32wb55cc" ]
31stm32wb55ce = [ "embassy-stm32/stm32wb55ce" ]
32stm32wb55cg = [ "embassy-stm32/stm32wb55cg" ]
33stm32wb55rc = [ "embassy-stm32/stm32wb55rc" ]
34stm32wb55re = [ "embassy-stm32/stm32wb55re" ]
35stm32wb55rg = [ "embassy-stm32/stm32wb55rg" ]
36stm32wb55vc = [ "embassy-stm32/stm32wb55vc" ]
37stm32wb55ve = [ "embassy-stm32/stm32wb55ve" ]
38stm32wb55vg = [ "embassy-stm32/stm32wb55vg" ]
39stm32wb55vy = [ "embassy-stm32/stm32wb55vy" ] \ No newline at end of file
diff --git a/embassy-stm32-wpan/build.rs b/embassy-stm32-wpan/build.rs
new file mode 100644
index 000000000..4edf73d59
--- /dev/null
+++ b/embassy-stm32-wpan/build.rs
@@ -0,0 +1,34 @@
1use std::env;
2
3fn main() {
4 match env::vars()
5 .map(|(a, _)| a)
6 .filter(|x| x.starts_with("CARGO_FEATURE_STM32"))
7 .get_one()
8 {
9 Ok(_) => {}
10 Err(GetOneError::None) => panic!("No stm32xx Cargo feature enabled"),
11 Err(GetOneError::Multiple) => panic!("Multiple stm32xx Cargo features enabled"),
12 }
13}
14
15enum GetOneError {
16 None,
17 Multiple,
18}
19
20trait IteratorExt: Iterator {
21 fn get_one(self) -> Result<Self::Item, GetOneError>;
22}
23
24impl<T: Iterator> IteratorExt for T {
25 fn get_one(mut self) -> Result<Self::Item, GetOneError> {
26 match self.next() {
27 None => Err(GetOneError::None),
28 Some(res) => match self.next() {
29 Some(_) => Err(GetOneError::Multiple),
30 None => Ok(res),
31 },
32 }
33 }
34}
diff --git a/embassy-stm32/src/tl_mbox/ble.rs b/embassy-stm32-wpan/src/ble.rs
index 062377999..19955a8a3 100644
--- a/embassy-stm32/src/tl_mbox/ble.rs
+++ b/embassy-stm32-wpan/src/ble.rs
@@ -1,26 +1,26 @@
1use embassy_futures::block_on; 1use core::mem::MaybeUninit;
2 2
3use super::cmd::CmdSerial; 3use embassy_stm32::ipcc::Ipcc;
4use super::consts::TlPacketType; 4
5use super::evt::EvtBox; 5use crate::cmd::{CmdPacket, CmdSerial};
6use super::unsafe_linked_list::LinkedListNode; 6use crate::consts::TlPacketType;
7use super::{ 7use crate::evt::EvtBox;
8 channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE, TL_CHANNEL, 8use crate::tables::BleTable;
9 TL_REF_TABLE, 9use crate::unsafe_linked_list::LinkedListNode;
10use crate::{
11 channels, BLE_CMD_BUFFER, CS_BUFFER, EVT_CHANNEL, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE, TL_REF_TABLE,
10}; 12};
11use crate::tl_mbox::cmd::CmdPacket;
12use crate::tl_mbox::ipcc::Ipcc;
13 13
14pub struct Ble; 14pub struct Ble;
15 15
16impl Ble { 16impl Ble {
17 pub fn enable() { 17 pub(super) fn enable() {
18 unsafe { 18 unsafe {
19 LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); 19 LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
20 20
21 TL_BLE_TABLE.as_mut_ptr().write_volatile(BleTable { 21 TL_BLE_TABLE = MaybeUninit::new(BleTable {
22 pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(), 22 pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(),
23 pcs_buffer: CS_BUFFER.as_mut_ptr().cast(), 23 pcs_buffer: CS_BUFFER.as_ptr().cast(),
24 pevt_queue: EVT_QUEUE.as_ptr().cast(), 24 pevt_queue: EVT_QUEUE.as_ptr().cast(),
25 phci_acl_data_buffer: HCI_ACL_DATA_BUFFER.as_mut_ptr().cast(), 25 phci_acl_data_buffer: HCI_ACL_DATA_BUFFER.as_mut_ptr().cast(),
26 }); 26 });
@@ -29,7 +29,7 @@ impl Ble {
29 Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, true); 29 Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, true);
30 } 30 }
31 31
32 pub fn evt_handler() { 32 pub(super) fn evt_handler() {
33 unsafe { 33 unsafe {
34 let mut node_ptr = core::ptr::null_mut(); 34 let mut node_ptr = core::ptr::null_mut();
35 let node_ptr_ptr: *mut _ = &mut node_ptr; 35 let node_ptr_ptr: *mut _ = &mut node_ptr;
@@ -40,25 +40,43 @@ impl Ble {
40 let event = node_ptr.cast(); 40 let event = node_ptr.cast();
41 let event = EvtBox::new(event); 41 let event = EvtBox::new(event);
42 42
43 block_on(TL_CHANNEL.send(event)); 43 EVT_CHANNEL.try_send(event).unwrap();
44 } 44 }
45 } 45 }
46 46
47 Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL); 47 Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL);
48 } 48 }
49 49
50 pub fn send_cmd(buf: &[u8]) { 50 pub(super) fn acl_data_handler() {
51 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, false);
52
53 // TODO: ACL data ack to the user
54 }
55
56 pub fn ble_send_cmd(buf: &[u8]) {
57 debug!("writing ble cmd");
58
51 unsafe { 59 unsafe {
52 let pcmd_buffer: *mut CmdPacket = (*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer; 60 let pcmd_buffer: *mut CmdPacket = (*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
53 let pcmd_serial: *mut CmdSerial = &mut (*pcmd_buffer).cmd_serial; 61 let pcmd_serial: *mut CmdSerial = &mut (*pcmd_buffer).cmdserial;
54 let pcmd_serial_buf: *mut u8 = pcmd_serial.cast(); 62 let pcmd_serial_buf: *mut u8 = pcmd_serial.cast();
55 63
56 core::ptr::copy(buf.as_ptr(), pcmd_serial_buf, buf.len()); 64 core::ptr::copy(buf.as_ptr(), pcmd_serial_buf, buf.len());
57 65
58 let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer; 66 let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
59 cmd_packet.cmd_serial.ty = TlPacketType::BleCmd as u8; 67 cmd_packet.cmdserial.ty = TlPacketType::BleCmd as u8;
60 } 68 }
61 69
62 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL); 70 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL);
63 } 71 }
72
73 #[allow(dead_code)] // Not used currently but reserved
74 pub(super) fn ble_send_acl_data() {
75 let cmd_packet = unsafe { &mut *(*TL_REF_TABLE.assume_init().ble_table).phci_acl_data_buffer };
76
77 cmd_packet.acl_data_serial.ty = TlPacketType::AclData as u8;
78
79 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL);
80 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, true);
81 }
64} 82}
diff --git a/embassy-stm32/src/tl_mbox/channels.rs b/embassy-stm32-wpan/src/channels.rs
index 25a065ba4..9a2be1cfa 100644
--- a/embassy-stm32/src/tl_mbox/channels.rs
+++ b/embassy-stm32-wpan/src/channels.rs
@@ -50,36 +50,30 @@
50//! 50//!
51 51
52pub mod cpu1 { 52pub mod cpu1 {
53 use crate::tl_mbox::ipcc::IpccChannel; 53 use embassy_stm32::ipcc::IpccChannel;
54 54
55 // Not used currently but reserved
56 pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1; 55 pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1;
57 // Not used currently but reserved
58 pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2; 56 pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2;
59 #[allow(dead_code)] // Not used currently but reserved
60 pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; 57 pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
61 #[allow(dead_code)] // Not used currently but reserved 58 #[allow(dead_code)] // Not used currently but reserved
62 pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3; 59 pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3;
63 #[allow(dead_code)] // Not used currently but reserved 60 #[allow(dead_code)] // Not used currently but reserved
64 pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; 61 pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
65 // Not used currently but reserved
66 pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4;
67 #[allow(dead_code)] // Not used currently but reserved 62 #[allow(dead_code)] // Not used currently but reserved
63 pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4;
68 pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; 64 pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
69 #[allow(dead_code)] // Not used currently but reserved 65 #[allow(dead_code)] // Not used currently but reserved
70 pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; 66 pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
71 #[allow(dead_code)] // Not used currently but reserved 67 #[allow(dead_code)] // Not used currently but reserved
72 pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; 68 pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
73 #[allow(dead_code)] // Not used currently but reserved
74 pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6; 69 pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6;
75} 70}
76 71
77pub mod cpu2 { 72pub mod cpu2 {
78 use crate::tl_mbox::ipcc::IpccChannel; 73 use embassy_stm32::ipcc::IpccChannel;
79 74
80 pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1; 75 pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1;
81 pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2; 76 pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2;
82 #[allow(dead_code)] // Not used currently but reserved
83 pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; 77 pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
84 #[allow(dead_code)] // Not used currently but reserved 78 #[allow(dead_code)] // Not used currently but reserved
85 pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; 79 pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
@@ -88,10 +82,8 @@ pub mod cpu2 {
88 #[allow(dead_code)] // Not used currently but reserved 82 #[allow(dead_code)] // Not used currently but reserved
89 pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; 83 pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
90 #[allow(dead_code)] // Not used currently but reserved 84 #[allow(dead_code)] // Not used currently but reserved
91 pub const IPCC_BLE_LLD_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; 85 pub const IPCC_BLE_LLDÇM0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
92 #[allow(dead_code)] // Not used currently but reserved
93 pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4; 86 pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4;
94 #[allow(dead_code)] // Not used currently but reserved
95 pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5; 87 pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5;
96 #[allow(dead_code)] // Not used currently but reserved 88 #[allow(dead_code)] // Not used currently but reserved
97 pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5; 89 pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5;
diff --git a/embassy-stm32-wpan/src/cmd.rs b/embassy-stm32-wpan/src/cmd.rs
new file mode 100644
index 000000000..1f7dae7f7
--- /dev/null
+++ b/embassy-stm32-wpan/src/cmd.rs
@@ -0,0 +1,77 @@
1use crate::evt::{EvtPacket, EvtSerial};
2use crate::{PacketHeader, TL_EVT_HEADER_SIZE};
3
4#[derive(Copy, Clone)]
5#[repr(C, packed)]
6pub struct Cmd {
7 pub cmd_code: u16,
8 pub payload_len: u8,
9 pub payload: [u8; 255],
10}
11
12impl Default for Cmd {
13 fn default() -> Self {
14 Self {
15 cmd_code: 0,
16 payload_len: 0,
17 payload: [0u8; 255],
18 }
19 }
20}
21
22#[derive(Copy, Clone, Default)]
23#[repr(C, packed)]
24pub struct CmdSerial {
25 pub ty: u8,
26 pub cmd: Cmd,
27}
28
29#[derive(Copy, Clone, Default)]
30#[repr(C, packed)]
31pub struct CmdPacket {
32 pub header: PacketHeader,
33 pub cmdserial: CmdSerial,
34}
35
36impl CmdPacket {
37 /// Writes an underlying CmdPacket into the provided buffer.
38 /// Returns a number of bytes that were written.
39 /// Returns an error if event kind is unknown or if provided buffer size is not enough.
40 #[allow(clippy::result_unit_err)]
41 pub fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
42 unsafe {
43 let cmd_ptr: *const CmdPacket = self;
44 let self_as_evt_ptr: *const EvtPacket = cmd_ptr.cast();
45 let evt_serial: *const EvtSerial = &(*self_as_evt_ptr).evt_serial;
46
47 let acl_data: *const AclDataPacket = cmd_ptr.cast();
48 let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
49 let acl_serial_buf: *const u8 = acl_serial.cast();
50
51 let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
52 if len > buf.len() {
53 return Err(());
54 }
55
56 core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len);
57
58 Ok(len)
59 }
60 }
61}
62
63#[derive(Copy, Clone)]
64#[repr(C, packed)]
65pub struct AclDataSerial {
66 pub ty: u8,
67 pub handle: u16,
68 pub length: u16,
69 pub acl_data: [u8; 1],
70}
71
72#[derive(Copy, Clone)]
73#[repr(C, packed)]
74pub struct AclDataPacket {
75 pub header: PacketHeader,
76 pub acl_data_serial: AclDataSerial,
77}
diff --git a/embassy-stm32/src/tl_mbox/consts.rs b/embassy-stm32-wpan/src/consts.rs
index e16a26cd0..caf26c06b 100644
--- a/embassy-stm32/src/tl_mbox/consts.rs
+++ b/embassy-stm32-wpan/src/consts.rs
@@ -1,4 +1,6 @@
1#[derive(PartialEq)] 1use core::convert::TryFrom;
2
3#[derive(Debug)]
2#[repr(C)] 4#[repr(C)]
3pub enum TlPacketType { 5pub enum TlPacketType {
4 BleCmd = 0x01, 6 BleCmd = 0x01,
diff --git a/embassy-stm32/src/tl_mbox/evt.rs b/embassy-stm32-wpan/src/evt.rs
index 47a8b72fd..b53fe506e 100644
--- a/embassy-stm32/src/tl_mbox/evt.rs
+++ b/embassy-stm32-wpan/src/evt.rs
@@ -3,9 +3,11 @@ use core::mem::MaybeUninit;
3use super::cmd::{AclDataPacket, AclDataSerial}; 3use super::cmd::{AclDataPacket, AclDataSerial};
4use super::consts::TlPacketType; 4use super::consts::TlPacketType;
5use super::{PacketHeader, TL_EVT_HEADER_SIZE}; 5use super::{PacketHeader, TL_EVT_HEADER_SIZE};
6use crate::tl_mbox::mm::MemoryManager; 6use crate::mm;
7 7
8/// the payload of [`Evt`] for a command status event 8/**
9 * The payload of `Evt` for a command status event
10 */
9#[derive(Copy, Clone)] 11#[derive(Copy, Clone)]
10#[repr(C, packed)] 12#[repr(C, packed)]
11pub struct CsEvt { 13pub struct CsEvt {
@@ -14,16 +16,39 @@ pub struct CsEvt {
14 pub cmd_code: u16, 16 pub cmd_code: u16,
15} 17}
16 18
17/// the payload of [`Evt`] for a command complete event 19/**
18#[derive(Clone, Copy, Default)] 20 * The payload of `Evt` for a command complete event
21 */
22#[derive(Copy, Clone, Default)]
19#[repr(C, packed)] 23#[repr(C, packed)]
20pub struct CcEvt { 24pub struct CcEvt {
21 pub num_cmd: u8, 25 pub num_cmd: u8,
22 pub cmd_code: u8, 26 pub cmd_code: u16,
23 pub payload: [u8; 1], 27 pub payload: [u8; 1],
24} 28}
25 29
26#[derive(Clone, Copy, Default)] 30impl CcEvt {
31 pub fn write(&self, buf: &mut [u8]) {
32 unsafe {
33 let len = core::mem::size_of::<CcEvt>();
34 assert!(buf.len() >= len);
35
36 let self_ptr: *const CcEvt = self;
37 let self_buf_ptr: *const u8 = self_ptr.cast();
38
39 core::ptr::copy(self_buf_ptr, buf.as_mut_ptr(), len);
40 }
41 }
42}
43
44#[derive(Copy, Clone, Default)]
45#[repr(C, packed)]
46pub struct AsynchEvt {
47 sub_evt_code: u16,
48 payload: [u8; 1],
49}
50
51#[derive(Copy, Clone, Default)]
27#[repr(C, packed)] 52#[repr(C, packed)]
28pub struct Evt { 53pub struct Evt {
29 pub evt_code: u8, 54 pub evt_code: u8,
@@ -31,7 +56,7 @@ pub struct Evt {
31 pub payload: [u8; 1], 56 pub payload: [u8; 1],
32} 57}
33 58
34#[derive(Clone, Copy, Default)] 59#[derive(Copy, Clone, Default)]
35#[repr(C, packed)] 60#[repr(C, packed)]
36pub struct EvtSerial { 61pub struct EvtSerial {
37 pub kind: u8, 62 pub kind: u8,
@@ -46,14 +71,26 @@ pub struct EvtSerial {
46/// Be careful that the asynchronous events reported by the CPU2 on the system channel do 71/// 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 72/// include the header and shall use `EvtPacket` format. Only the command response format on the
48/// system channel is different. 73/// system channel is different.
49#[derive(Clone, Copy, Default)] 74#[derive(Copy, Clone, Default)]
50#[repr(C, packed)] 75#[repr(C, packed)]
51pub struct EvtPacket { 76pub struct EvtPacket {
52 pub header: PacketHeader, 77 pub header: PacketHeader,
53 pub evt_serial: EvtSerial, 78 pub evt_serial: EvtSerial,
54} 79}
55 80
56/// Smart pointer to the [`EvtPacket`] that will dispose of it automatically on drop 81impl EvtPacket {
82 pub fn kind(&self) -> u8 {
83 self.evt_serial.kind
84 }
85
86 pub fn evt(&self) -> &Evt {
87 &self.evt_serial.evt
88 }
89}
90
91/// smart pointer to the [`EvtPacket`] that will dispose of [`EvtPacket`] buffer automatically
92/// on [`Drop`]
93#[derive(Debug)]
57pub struct EvtBox { 94pub struct EvtBox {
58 ptr: *mut EvtPacket, 95 ptr: *mut EvtPacket,
59} 96}
@@ -64,7 +101,7 @@ impl EvtBox {
64 Self { ptr } 101 Self { ptr }
65 } 102 }
66 103
67 /// Copies the event data from inner pointer and returns and event structure 104 /// copies event data from inner pointer and returns an event structure
68 pub fn evt(&self) -> EvtPacket { 105 pub fn evt(&self) -> EvtPacket {
69 let mut evt = MaybeUninit::uninit(); 106 let mut evt = MaybeUninit::uninit();
70 unsafe { 107 unsafe {
@@ -73,28 +110,11 @@ impl EvtBox {
73 } 110 }
74 } 111 }
75 112
76 /// Returns the size of a buffer required to hold this event 113 /// writes an underlying [`EvtPacket`] into the provided buffer.
77 pub fn size(&self) -> Result<usize, ()> { 114 /// Returns the number of bytes that were written.
78 unsafe { 115 /// Returns an error if event kind is unknown or if provided buffer size is not enough.
79 let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?; 116 #[allow(clippy::result_unit_err)]
80 117 pub fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
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 unsafe { 118 unsafe {
99 let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?; 119 let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
100 120
@@ -127,10 +147,30 @@ impl EvtBox {
127 } 147 }
128 } 148 }
129 } 149 }
150
151 /// returns the size of a buffer required to hold this event
152 #[allow(clippy::result_unit_err)]
153 pub fn size(&self) -> Result<usize, ()> {
154 unsafe {
155 let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
156
157 let evt_data: *const EvtPacket = self.ptr.cast();
158 let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
159
160 let acl_data: *const AclDataPacket = self.ptr.cast();
161 let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
162
163 if let TlPacketType::AclData = evt_kind {
164 Ok((*acl_serial).length as usize + 5)
165 } else {
166 Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE)
167 }
168 }
169 }
130} 170}
131 171
132impl Drop for EvtBox { 172impl Drop for EvtBox {
133 fn drop(&mut self) { 173 fn drop(&mut self) {
134 MemoryManager::evt_drop(self.ptr); 174 mm::MemoryManager::evt_drop(self.ptr);
135 } 175 }
136} 176}
diff --git a/embassy-stm32-wpan/src/fmt.rs b/embassy-stm32-wpan/src/fmt.rs
new file mode 100644
index 000000000..066970813
--- /dev/null
+++ b/embassy-stm32-wpan/src/fmt.rs
@@ -0,0 +1,225 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features.");
6
7macro_rules! assert {
8 ($($x:tt)*) => {
9 {
10 #[cfg(not(feature = "defmt"))]
11 ::core::assert!($($x)*);
12 #[cfg(feature = "defmt")]
13 ::defmt::assert!($($x)*);
14 }
15 };
16}
17
18macro_rules! assert_eq {
19 ($($x:tt)*) => {
20 {
21 #[cfg(not(feature = "defmt"))]
22 ::core::assert_eq!($($x)*);
23 #[cfg(feature = "defmt")]
24 ::defmt::assert_eq!($($x)*);
25 }
26 };
27}
28
29macro_rules! assert_ne {
30 ($($x:tt)*) => {
31 {
32 #[cfg(not(feature = "defmt"))]
33 ::core::assert_ne!($($x)*);
34 #[cfg(feature = "defmt")]
35 ::defmt::assert_ne!($($x)*);
36 }
37 };
38}
39
40macro_rules! debug_assert {
41 ($($x:tt)*) => {
42 {
43 #[cfg(not(feature = "defmt"))]
44 ::core::debug_assert!($($x)*);
45 #[cfg(feature = "defmt")]
46 ::defmt::debug_assert!($($x)*);
47 }
48 };
49}
50
51macro_rules! debug_assert_eq {
52 ($($x:tt)*) => {
53 {
54 #[cfg(not(feature = "defmt"))]
55 ::core::debug_assert_eq!($($x)*);
56 #[cfg(feature = "defmt")]
57 ::defmt::debug_assert_eq!($($x)*);
58 }
59 };
60}
61
62macro_rules! debug_assert_ne {
63 ($($x:tt)*) => {
64 {
65 #[cfg(not(feature = "defmt"))]
66 ::core::debug_assert_ne!($($x)*);
67 #[cfg(feature = "defmt")]
68 ::defmt::debug_assert_ne!($($x)*);
69 }
70 };
71}
72
73macro_rules! todo {
74 ($($x:tt)*) => {
75 {
76 #[cfg(not(feature = "defmt"))]
77 ::core::todo!($($x)*);
78 #[cfg(feature = "defmt")]
79 ::defmt::todo!($($x)*);
80 }
81 };
82}
83
84macro_rules! unreachable {
85 ($($x:tt)*) => {
86 {
87 #[cfg(not(feature = "defmt"))]
88 ::core::unreachable!($($x)*);
89 #[cfg(feature = "defmt")]
90 ::defmt::unreachable!($($x)*);
91 }
92 };
93}
94
95macro_rules! panic {
96 ($($x:tt)*) => {
97 {
98 #[cfg(not(feature = "defmt"))]
99 ::core::panic!($($x)*);
100 #[cfg(feature = "defmt")]
101 ::defmt::panic!($($x)*);
102 }
103 };
104}
105
106macro_rules! trace {
107 ($s:literal $(, $x:expr)* $(,)?) => {
108 {
109 #[cfg(feature = "log")]
110 ::log::trace!($s $(, $x)*);
111 #[cfg(feature = "defmt")]
112 ::defmt::trace!($s $(, $x)*);
113 #[cfg(not(any(feature = "log", feature="defmt")))]
114 let _ = ($( & $x ),*);
115 }
116 };
117}
118
119macro_rules! debug {
120 ($s:literal $(, $x:expr)* $(,)?) => {
121 {
122 #[cfg(feature = "log")]
123 ::log::debug!($s $(, $x)*);
124 #[cfg(feature = "defmt")]
125 ::defmt::debug!($s $(, $x)*);
126 #[cfg(not(any(feature = "log", feature="defmt")))]
127 let _ = ($( & $x ),*);
128 }
129 };
130}
131
132macro_rules! info {
133 ($s:literal $(, $x:expr)* $(,)?) => {
134 {
135 #[cfg(feature = "log")]
136 ::log::info!($s $(, $x)*);
137 #[cfg(feature = "defmt")]
138 ::defmt::info!($s $(, $x)*);
139 #[cfg(not(any(feature = "log", feature="defmt")))]
140 let _ = ($( & $x ),*);
141 }
142 };
143}
144
145macro_rules! warn {
146 ($s:literal $(, $x:expr)* $(,)?) => {
147 {
148 #[cfg(feature = "log")]
149 ::log::warn!($s $(, $x)*);
150 #[cfg(feature = "defmt")]
151 ::defmt::warn!($s $(, $x)*);
152 #[cfg(not(any(feature = "log", feature="defmt")))]
153 let _ = ($( & $x ),*);
154 }
155 };
156}
157
158macro_rules! error {
159 ($s:literal $(, $x:expr)* $(,)?) => {
160 {
161 #[cfg(feature = "log")]
162 ::log::error!($s $(, $x)*);
163 #[cfg(feature = "defmt")]
164 ::defmt::error!($s $(, $x)*);
165 #[cfg(not(any(feature = "log", feature="defmt")))]
166 let _ = ($( & $x ),*);
167 }
168 };
169}
170
171#[cfg(feature = "defmt")]
172macro_rules! unwrap {
173 ($($x:tt)*) => {
174 ::defmt::unwrap!($($x)*)
175 };
176}
177
178#[cfg(not(feature = "defmt"))]
179macro_rules! unwrap {
180 ($arg:expr) => {
181 match $crate::fmt::Try::into_result($arg) {
182 ::core::result::Result::Ok(t) => t,
183 ::core::result::Result::Err(e) => {
184 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
185 }
186 }
187 };
188 ($arg:expr, $($msg:expr),+ $(,)? ) => {
189 match $crate::fmt::Try::into_result($arg) {
190 ::core::result::Result::Ok(t) => t,
191 ::core::result::Result::Err(e) => {
192 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
193 }
194 }
195 }
196}
197
198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
199pub struct NoneError;
200
201pub trait Try {
202 type Ok;
203 type Error;
204 fn into_result(self) -> Result<Self::Ok, Self::Error>;
205}
206
207impl<T> Try for Option<T> {
208 type Ok = T;
209 type Error = NoneError;
210
211 #[inline]
212 fn into_result(self) -> Result<T, NoneError> {
213 self.ok_or(NoneError)
214 }
215}
216
217impl<T, E> Try for Result<T, E> {
218 type Ok = T;
219 type Error = E;
220
221 #[inline]
222 fn into_result(self) -> Self {
223 self
224 }
225}
diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs
new file mode 100644
index 000000000..c37b67dc4
--- /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.
4pub mod fmt;
5
6use core::mem::MaybeUninit;
7
8use cmd::CmdPacket;
9use embassy_futures::block_on;
10use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
11use embassy_stm32::interrupt;
12use embassy_stm32::interrupt::typelevel::Interrupt;
13use embassy_stm32::ipcc::{Config, Ipcc};
14use embassy_stm32::peripherals::IPCC;
15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
16use embassy_sync::channel::Channel;
17use embassy_sync::signal::Signal;
18use evt::{CcEvt, EvtBox};
19use tables::{
20 BleTable, DeviceInfoTable, Mac802_15_4Table, MemManagerTable, RefTable, SysTable, ThreadTable, TracesTable,
21 WirelessFwInfoTable,
22};
23use unsafe_linked_list::LinkedListNode;
24
25pub mod ble;
26pub mod channels;
27pub mod cmd;
28pub mod consts;
29pub mod evt;
30pub mod mm;
31pub mod rc;
32pub mod shci;
33pub mod sys;
34pub mod tables;
35pub mod unsafe_linked_list;
36
37/// Interrupt handler.
38pub struct ReceiveInterruptHandler {}
39
40impl interrupt::typelevel::Handler<interrupt::typelevel::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
54pub struct TransmitInterruptHandler {}
55
56impl interrupt::typelevel::Handler<interrupt::typelevel::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"]
76pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
77
78#[link_section = "MB_MEM1"]
79static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit();
80
81#[link_section = "MB_MEM1"]
82static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit();
83
84#[link_section = "MB_MEM1"]
85static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit();
86
87#[link_section = "MB_MEM1"]
88static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit();
89
90#[link_section = "MB_MEM1"]
91static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit();
92
93#[link_section = "MB_MEM1"]
94static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit();
95
96#[link_section = "MB_MEM1"]
97static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit();
98
99#[link_section = "MB_MEM2"]
100static mut FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
101
102// Not in shared RAM
103static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
104
105#[allow(dead_code)] // Not used currently but reserved
106#[link_section = "MB_MEM2"]
107static mut TRACES_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
108
109type PacketHeader = LinkedListNode;
110
111const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::<PacketHeader>();
112const TL_EVT_HEADER_SIZE: usize = 3;
113const TL_CS_EVT_SIZE: usize = core::mem::size_of::<evt::CsEvt>();
114
115#[link_section = "MB_MEM2"]
116static 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"]
120static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
121
122#[link_section = "MB_MEM2"]
123static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
124
125#[link_section = "MB_MEM2"]
126pub 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 */
141const CFG_TLBLE_EVT_QUEUE_LENGTH: usize = 5;
142const CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255;
143const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE;
144
145const fn divc(x: usize, y: usize) -> usize {
146 ((x) + (y) - 1) / (y)
147}
148
149const 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"]
152static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit();
153
154#[link_section = "MB_MEM2"]
155static 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"]
159static 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"]
163static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
164
165#[link_section = "MB_MEM2"]
166// fuck these "magic" numbers from ST ---v---v
167static 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
171static EVT_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 32> = Channel::new();
172
173/// last received Command Complete event
174static LAST_CC_EVT: Signal<CriticalSectionRawMutex, CcEvt> = Signal::new();
175
176static STATE: Signal<CriticalSectionRawMutex, ()> = Signal::new();
177
178pub struct TlMbox<'d> {
179 _ipcc: PeripheralRef<'d, IPCC>,
180}
181
182impl<'d> TlMbox<'d> {
183 pub fn init(
184 ipcc: impl Peripheral<P = IPCC> + 'd,
185 _irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler>
186 + interrupt::typelevel::Binding<interrupt::typelevel::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::typelevel::IPCC_C1_RX::unpend();
227 interrupt::typelevel::IPCC_C1_TX::unpend();
228
229 unsafe { interrupt::typelevel::IPCC_C1_RX::enable() };
230 unsafe { interrupt::typelevel::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}
diff --git a/embassy-stm32-wpan/src/mm.rs b/embassy-stm32-wpan/src/mm.rs
new file mode 100644
index 000000000..ed13b0dbf
--- /dev/null
+++ b/embassy-stm32-wpan/src/mm.rs
@@ -0,0 +1,75 @@
1//! Memory manager routines
2
3use core::mem::MaybeUninit;
4
5use embassy_stm32::ipcc::Ipcc;
6
7use crate::evt::EvtPacket;
8use crate::tables::MemManagerTable;
9use crate::unsafe_linked_list::LinkedListNode;
10use crate::{
11 channels, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, SYS_SPARE_EVT_BUF,
12 TL_MEM_MANAGER_TABLE, TL_REF_TABLE,
13};
14
15pub(super) struct MemoryManager;
16
17impl MemoryManager {
18 pub fn enable() {
19 unsafe {
20 LinkedListNode::init_head(FREE_BUF_QUEUE.as_mut_ptr());
21 LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
22
23 TL_MEM_MANAGER_TABLE = MaybeUninit::new(MemManagerTable {
24 spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
25 spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
26 blepool: EVT_POOL.as_ptr().cast(),
27 blepoolsize: POOL_SIZE as u32,
28 pevt_free_buffer_queue: FREE_BUF_QUEUE.as_mut_ptr(),
29 traces_evt_pool: core::ptr::null(),
30 tracespoolsize: 0,
31 });
32 }
33 }
34
35 pub fn evt_drop(evt: *mut EvtPacket) {
36 unsafe {
37 let list_node = evt.cast();
38
39 LinkedListNode::insert_tail(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), list_node);
40
41 let channel_is_busy = Ipcc::c1_is_active_flag(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
42
43 // postpone event buffer freeing to IPCC interrupt handler
44 if channel_is_busy {
45 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, true);
46 } else {
47 Self::send_free_buf();
48 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
49 }
50 }
51 }
52
53 /// gives free event buffers back to CPU2 from local buffer queue
54 pub fn send_free_buf() {
55 unsafe {
56 let mut node_ptr = core::ptr::null_mut();
57 let node_ptr_ptr: *mut _ = &mut node_ptr;
58
59 while !LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
60 LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), node_ptr_ptr);
61 LinkedListNode::insert_tail(
62 (*(*TL_REF_TABLE.as_ptr()).mem_manager_table).pevt_free_buffer_queue,
63 node_ptr,
64 );
65 }
66 }
67 }
68
69 /// free buffer channel interrupt handler
70 pub fn free_buf_handler() {
71 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false);
72 Self::send_free_buf();
73 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
74 }
75}
diff --git a/embassy-stm32-wpan/src/rc.rs b/embassy-stm32-wpan/src/rc.rs
new file mode 100644
index 000000000..aae2265ed
--- /dev/null
+++ b/embassy-stm32-wpan/src/rc.rs
@@ -0,0 +1,50 @@
1use crate::ble::Ble;
2use crate::consts::TlPacketType;
3use crate::{shci, TlMbox, STATE};
4
5pub struct RadioCoprocessor<'d> {
6 mbox: TlMbox<'d>,
7 rx_buf: [u8; 500],
8}
9
10impl<'d> RadioCoprocessor<'d> {
11 pub fn new(mbox: TlMbox<'d>) -> Self {
12 Self {
13 mbox,
14 rx_buf: [0u8; 500],
15 }
16 }
17
18 pub fn write(&self, buf: &[u8]) {
19 let cmd_code = buf[0];
20 let cmd = TlPacketType::try_from(cmd_code).unwrap();
21
22 match &cmd {
23 TlPacketType::BleCmd => Ble::ble_send_cmd(buf),
24 _ => todo!(),
25 }
26 }
27
28 pub async fn read(&mut self) -> &[u8] {
29 loop {
30 STATE.wait().await;
31
32 while let Some(evt) = self.mbox.dequeue_event() {
33 let event = evt.evt();
34
35 evt.write(&mut self.rx_buf).unwrap();
36
37 if event.kind() == 18 {
38 shci::shci_ble_init(Default::default());
39 self.rx_buf[0] = 0x04;
40 }
41 }
42
43 if self.mbox.pop_last_cc_evt().is_some() {
44 continue;
45 }
46
47 return &self.rx_buf;
48 }
49 }
50}
diff --git a/embassy-stm32/src/tl_mbox/shci.rs b/embassy-stm32-wpan/src/shci.rs
index 6b5b2dd19..8537995ff 100644
--- a/embassy-stm32/src/tl_mbox/shci.rs
+++ b/embassy-stm32-wpan/src/shci.rs
@@ -1,16 +1,10 @@
1//! HCI commands for system channel
2
3use super::cmd::CmdPacket; 1use super::cmd::CmdPacket;
4use super::consts::TlPacketType; 2use super::consts::TlPacketType;
5use super::{channels, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE, TL_SYS_TABLE}; 3use super::{sys, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE, TL_SYS_TABLE};
6use crate::tl_mbox::ipcc::Ipcc;
7 4
8const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66; 5const 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 6
13#[derive(Clone, Copy)] 7#[derive(Debug, Clone, Copy)]
14#[repr(C, packed)] 8#[repr(C, packed)]
15pub struct ShciBleInitCmdParam { 9pub struct ShciBleInitCmdParam {
16 /// NOT USED CURRENTLY 10 /// NOT USED CURRENTLY
@@ -63,39 +57,44 @@ impl Default for ShciBleInitCmdParam {
63 } 57 }
64} 58}
65 59
66#[derive(Clone, Copy, Default)] 60#[derive(Debug, Clone, Copy, Default)]
67#[repr(C, packed)] 61#[repr(C, packed)]
68pub struct ShciHeader { 62pub struct ShciHeader {
69 metadata: [u32; 3], 63 metadata: [u32; 3],
70} 64}
71 65
72#[derive(Clone, Copy)] 66#[derive(Debug, Clone, Copy)]
73#[repr(C, packed)] 67#[repr(C, packed)]
74pub struct ShciBleInitCmdPacket { 68pub struct ShciBleInitCmdPacket {
75 header: ShciHeader, 69 header: ShciHeader,
76 param: ShciBleInitCmdParam, 70 param: ShciBleInitCmdParam,
77} 71}
78 72
73pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
74#[allow(dead_code)] // Not used currently but reserved
75const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
76
79pub fn shci_ble_init(param: ShciBleInitCmdParam) { 77pub fn shci_ble_init(param: ShciBleInitCmdParam) {
78 debug!("sending SHCI");
79
80 let mut packet = ShciBleInitCmdPacket { 80 let mut packet = ShciBleInitCmdPacket {
81 header: ShciHeader::default(), 81 header: ShciHeader::default(),
82 param, 82 param,
83 }; 83 };
84 84
85 let packet_ptr: *mut ShciBleInitCmdPacket = &mut packet; 85 let packet_ptr: *mut _ = &mut packet;
86 86
87 unsafe { 87 unsafe {
88 let cmd_ptr: *mut CmdPacket = packet_ptr.cast(); 88 let cmd_ptr: *mut CmdPacket = packet_ptr.cast();
89 89
90 (*cmd_ptr).cmd_serial.cmd.cmd_code = SCHI_OPCODE_BLE_INIT; 90 (*cmd_ptr).cmdserial.cmd.cmd_code = SCHI_OPCODE_BLE_INIT;
91 (*cmd_ptr).cmd_serial.cmd.payload_len = core::mem::size_of::<ShciBleInitCmdParam>() as u8; 91 (*cmd_ptr).cmdserial.cmd.payload_len = core::mem::size_of::<ShciBleInitCmdParam>() as u8;
92 92
93 let cmd_buf = &mut *(*TL_SYS_TABLE.as_mut_ptr()).pcmd_buffer; 93 let p_cmd_buffer = &mut *(*TL_SYS_TABLE.as_mut_ptr()).pcmd_buffer;
94 core::ptr::write(cmd_buf, *cmd_ptr); 94 core::ptr::write(p_cmd_buffer, *cmd_ptr);
95 95
96 cmd_buf.cmd_serial.ty = TlPacketType::SysCmd as u8; 96 p_cmd_buffer.cmdserial.ty = TlPacketType::SysCmd as u8;
97 97
98 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL); 98 sys::Sys::send_cmd();
99 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
100 } 99 }
101} 100}
diff --git a/embassy-stm32/src/tl_mbox/sys.rs b/embassy-stm32-wpan/src/sys.rs
index 9685fb920..a19d12d27 100644
--- a/embassy-stm32/src/tl_mbox/sys.rs
+++ b/embassy-stm32-wpan/src/sys.rs
@@ -1,11 +1,12 @@
1use embassy_futures::block_on; 1use core::mem::MaybeUninit;
2 2
3use super::cmd::{CmdPacket, CmdSerial}; 3use embassy_stm32::ipcc::Ipcc;
4use super::consts::TlPacketType; 4
5use super::evt::{CcEvt, EvtBox, EvtSerial}; 5use crate::cmd::{CmdPacket, CmdSerial};
6use super::unsafe_linked_list::LinkedListNode; 6use crate::evt::{CcEvt, EvtBox, EvtSerial};
7use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_CHANNEL, TL_REF_TABLE, TL_SYS_TABLE}; 7use crate::tables::SysTable;
8use crate::tl_mbox::ipcc::Ipcc; 8use crate::unsafe_linked_list::LinkedListNode;
9use crate::{channels, EVT_CHANNEL, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_SYS_TABLE};
9 10
10pub struct Sys; 11pub struct Sys;
11 12
@@ -14,34 +15,15 @@ impl Sys {
14 unsafe { 15 unsafe {
15 LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr()); 16 LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
16 17
17 TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable { 18 TL_SYS_TABLE = MaybeUninit::new(SysTable {
18 pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(), 19 pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
19 sys_queue: SYSTEM_EVT_QUEUE.as_ptr(), 20 sys_queue: SYSTEM_EVT_QUEUE.as_ptr(),
20 }); 21 })
21 } 22 }
22 23
23 Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, true); 24 Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, true);
24 } 25 }
25 26
26 pub fn evt_handler() {
27 unsafe {
28 let mut node_ptr = core::ptr::null_mut();
29 let node_ptr_ptr: *mut _ = &mut node_ptr;
30
31 while !LinkedListNode::is_empty(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
32 LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr(), node_ptr_ptr);
33
34 let event = node_ptr.cast();
35 let event = EvtBox::new(event);
36
37 // TODO: not really happy about this
38 block_on(TL_CHANNEL.send(event));
39 }
40 }
41
42 Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL);
43 }
44
45 pub fn cmd_evt_handler() -> CcEvt { 27 pub fn cmd_evt_handler() -> CcEvt {
46 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false); 28 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false);
47 29
@@ -55,29 +37,34 @@ impl Sys {
55 // 4. CcEvt type is the actual SHCI response 37 // 4. CcEvt type is the actual SHCI response
56 // 5. profit 38 // 5. profit
57 unsafe { 39 unsafe {
58 let cmd: *const CmdPacket = (*TL_SYS_TABLE.as_ptr()).pcmd_buffer; 40 let pcmd: *const CmdPacket = (*TL_SYS_TABLE.as_ptr()).pcmd_buffer;
59 let cmd_serial: *const CmdSerial = &(*cmd).cmd_serial; 41 let cmd_serial: *const CmdSerial = &(*pcmd).cmdserial;
60 let evt_serial: *const EvtSerial = cmd_serial.cast(); 42 let evt_serial: *const EvtSerial = cmd_serial.cast();
61 let cc = (*evt_serial).evt.payload.as_ptr().cast(); 43 let cc: *const CcEvt = (*evt_serial).evt.payload.as_ptr().cast();
62 *cc 44 *cc
63 } 45 }
64 } 46 }
65 47
66 #[allow(dead_code)] 48 pub fn evt_handler() {
67 pub fn send_cmd(buf: &[u8]) {
68 unsafe { 49 unsafe {
69 // TODO: check this 50 let mut node_ptr = core::ptr::null_mut();
70 let cmd_buffer = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer; 51 let node_ptr_ptr: *mut _ = &mut node_ptr;
71 let cmd_serial: *mut CmdSerial = &mut cmd_buffer.cmd_serial;
72 let cmd_serial_buf = cmd_serial.cast();
73 52
74 core::ptr::copy(buf.as_ptr(), cmd_serial_buf, buf.len()); 53 while !LinkedListNode::is_empty(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
54 LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr(), node_ptr_ptr);
75 55
76 let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer; 56 let event = node_ptr.cast();
77 cmd_packet.cmd_serial.ty = TlPacketType::SysCmd as u8; 57 let event = EvtBox::new(event);
78 58
79 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL); 59 EVT_CHANNEL.try_send(event).unwrap();
80 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true); 60 }
81 } 61 }
62
63 Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL);
64 }
65
66 pub fn send_cmd() {
67 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL);
68 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
82 } 69 }
83} 70}
diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs
new file mode 100644
index 000000000..151216958
--- /dev/null
+++ b/embassy-stm32-wpan/src/tables.rs
@@ -0,0 +1,175 @@
1use bit_field::BitField;
2
3use crate::cmd::{AclDataPacket, CmdPacket};
4use crate::unsafe_linked_list::LinkedListNode;
5
6#[derive(Debug, Copy, Clone)]
7#[repr(C, packed)]
8pub struct SafeBootInfoTable {
9 version: u32,
10}
11
12#[derive(Debug, Copy, Clone)]
13#[repr(C, packed)]
14pub struct RssInfoTable {
15 pub version: u32,
16 pub memory_size: u32,
17 pub rss_info: u32,
18}
19
20/**
21 * Version
22 * [0:3] = Build - 0: Untracked - 15:Released - x: Tracked version
23 * [4:7] = branch - 0: Mass Market - x: ...
24 * [8:15] = Subversion
25 * [16:23] = Version minor
26 * [24:31] = Version major
27 *
28 * Memory Size
29 * [0:7] = Flash ( Number of 4k sector)
30 * [8:15] = Reserved ( Shall be set to 0 - may be used as flash extension )
31 * [16:23] = SRAM2b ( Number of 1k sector)
32 * [24:31] = SRAM2a ( Number of 1k sector)
33 */
34#[derive(Debug, Copy, Clone)]
35#[repr(C, packed)]
36pub struct WirelessFwInfoTable {
37 pub version: u32,
38 pub memory_size: u32,
39 pub thread_info: u32,
40 pub ble_info: u32,
41}
42
43impl WirelessFwInfoTable {
44 pub fn version_major(&self) -> u8 {
45 let version = self.version;
46 (version.get_bits(24..31) & 0xff) as u8
47 }
48
49 pub fn version_minor(&self) -> u8 {
50 let version = self.version;
51 (version.clone().get_bits(16..23) & 0xff) as u8
52 }
53
54 pub fn subversion(&self) -> u8 {
55 let version = self.version;
56 (version.clone().get_bits(8..15) & 0xff) as u8
57 }
58
59 /// Size of FLASH, expressed in number of 4K sectors.
60 pub fn flash_size(&self) -> u8 {
61 let memory_size = self.memory_size;
62 (memory_size.clone().get_bits(0..7) & 0xff) as u8
63 }
64
65 /// Size of SRAM2a, expressed in number of 1K sectors.
66 pub fn sram2a_size(&self) -> u8 {
67 let memory_size = self.memory_size;
68 (memory_size.clone().get_bits(24..31) & 0xff) as u8
69 }
70
71 /// Size of SRAM2b, expressed in number of 1K sectors.
72 pub fn sram2b_size(&self) -> u8 {
73 let memory_size = self.memory_size;
74 (memory_size.clone().get_bits(16..23) & 0xff) as u8
75 }
76}
77
78#[derive(Debug, Clone)]
79#[repr(C, align(4))]
80pub struct DeviceInfoTable {
81 pub safe_boot_info_table: SafeBootInfoTable,
82 pub rss_info_table: RssInfoTable,
83 pub wireless_fw_info_table: WirelessFwInfoTable,
84}
85
86#[derive(Debug)]
87#[repr(C, align(4))]
88pub struct BleTable {
89 pub pcmd_buffer: *mut CmdPacket,
90 pub pcs_buffer: *const u8,
91 pub pevt_queue: *const u8,
92 pub phci_acl_data_buffer: *mut AclDataPacket,
93}
94
95#[derive(Debug)]
96#[repr(C, align(4))]
97pub struct ThreadTable {
98 pub nostack_buffer: *const u8,
99 pub clicmdrsp_buffer: *const u8,
100 pub otcmdrsp_buffer: *const u8,
101}
102
103// TODO: use later
104#[derive(Debug)]
105#[repr(C, align(4))]
106pub struct LldTestsTable {
107 pub clicmdrsp_buffer: *const u8,
108 pub m0cmd_buffer: *const u8,
109}
110
111// TODO: use later
112#[derive(Debug)]
113#[repr(C, align(4))]
114pub struct BleLldTable {
115 pub cmdrsp_buffer: *const u8,
116 pub m0cmd_buffer: *const u8,
117}
118
119// TODO: use later
120#[derive(Debug)]
121#[repr(C, align(4))]
122pub struct ZigbeeTable {
123 pub notif_m0_to_m4_buffer: *const u8,
124 pub appli_cmd_m4_to_m0_bufer: *const u8,
125 pub request_m0_to_m4_buffer: *const u8,
126}
127
128#[derive(Debug)]
129#[repr(C, align(4))]
130pub struct SysTable {
131 pub pcmd_buffer: *mut CmdPacket,
132 pub sys_queue: *const LinkedListNode,
133}
134
135#[derive(Debug)]
136#[repr(C, align(4))]
137pub struct MemManagerTable {
138 pub spare_ble_buffer: *const u8,
139 pub spare_sys_buffer: *const u8,
140
141 pub blepool: *const u8,
142 pub blepoolsize: u32,
143
144 pub pevt_free_buffer_queue: *mut LinkedListNode,
145
146 pub traces_evt_pool: *const u8,
147 pub tracespoolsize: u32,
148}
149
150#[derive(Debug)]
151#[repr(C, align(4))]
152pub struct TracesTable {
153 pub traces_queue: *const u8,
154}
155
156#[derive(Debug)]
157#[repr(C, align(4))]
158pub struct Mac802_15_4Table {
159 pub p_cmdrsp_buffer: *const u8,
160 pub p_notack_buffer: *const u8,
161 pub evt_queue: *const u8,
162}
163
164/// Reference table. Contains pointers to all other tables.
165#[derive(Debug, Copy, Clone)]
166#[repr(C)]
167pub struct RefTable {
168 pub device_info_table: *const DeviceInfoTable,
169 pub ble_table: *const BleTable,
170 pub thread_table: *const ThreadTable,
171 pub sys_table: *const SysTable,
172 pub mem_manager_table: *const MemManagerTable,
173 pub traces_table: *const TracesTable,
174 pub mac_802_15_4_table: *const Mac802_15_4Table,
175}
diff --git a/embassy-stm32/src/tl_mbox/unsafe_linked_list.rs b/embassy-stm32-wpan/src/unsafe_linked_list.rs
index 482e2bf5a..52c106fa2 100644
--- a/embassy-stm32/src/tl_mbox/unsafe_linked_list.rs
+++ b/embassy-stm32-wpan/src/unsafe_linked_list.rs
@@ -57,6 +57,7 @@ impl LinkedListNode {
57 }); 57 });
58 } 58 }
59 59
60 /// Remove `node` from the linked list
60 pub unsafe fn remove_node(mut node: *mut LinkedListNode) { 61 pub unsafe fn remove_node(mut node: *mut LinkedListNode) {
61 interrupt::free(|_| { 62 interrupt::free(|_| {
62 (*(*node).prev).next = (*node).next; 63 (*(*node).prev).next = (*node).next;
@@ -64,6 +65,7 @@ impl LinkedListNode {
64 }); 65 });
65 } 66 }
66 67
68 /// Remove `list_head` into `node`
67 pub unsafe fn remove_head(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) { 69 pub unsafe fn remove_head(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
68 interrupt::free(|_| { 70 interrupt::free(|_| {
69 *node = (*list_head).next; 71 *node = (*list_head).next;
@@ -71,10 +73,11 @@ impl LinkedListNode {
71 }); 73 });
72 } 74 }
73 75
74 pub unsafe fn remove_tail(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) { 76 /// Remove `list_tail` into `node`
77 pub unsafe fn remove_tail(mut list_tail: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
75 interrupt::free(|_| { 78 interrupt::free(|_| {
76 *node = (*list_head).prev; 79 *node = (*list_tail).prev;
77 Self::remove_node((*list_head).prev); 80 Self::remove_node((*list_tail).prev);
78 }); 81 });
79 } 82 }
80 83
diff --git a/embassy-stm32/src/tl_mbox/ipcc.rs b/embassy-stm32/src/ipcc.rs
index d1ac731ed..8bb0774b8 100644
--- a/embassy-stm32/src/tl_mbox/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -167,8 +167,68 @@ impl sealed::Instance for crate::peripherals::IPCC {
167} 167}
168 168
169unsafe fn _configure_pwr() { 169unsafe fn _configure_pwr() {
170 let pwr = crate::pac::PWR;
170 let rcc = crate::pac::RCC; 171 let rcc = crate::pac::RCC;
171 172
173 rcc.cfgr().modify(|w| w.set_stopwuck(true));
174
175 pwr.cr1().modify(|w| w.set_dbp(true));
176 pwr.cr1().modify(|w| w.set_dbp(true));
177
178 // configure LSE
179 rcc.bdcr().modify(|w| w.set_lseon(true));
180
181 // select system clock source = PLL
182 // set PLL coefficients
183 // m: 2,
184 // n: 12,
185 // r: 3,
186 // q: 4,
187 // p: 3,
188 let src_bits = 0b11;
189 let pllp = (3 - 1) & 0b11111;
190 let pllq = (4 - 1) & 0b111;
191 let pllr = (3 - 1) & 0b111;
192 let plln = 12 & 0b1111111;
193 let pllm = (2 - 1) & 0b111;
194 rcc.pllcfgr().modify(|w| {
195 w.set_pllsrc(src_bits);
196 w.set_pllm(pllm);
197 w.set_plln(plln);
198 w.set_pllr(pllr);
199 w.set_pllp(pllp);
200 w.set_pllpen(true);
201 w.set_pllq(pllq);
202 w.set_pllqen(true);
203 });
204 // enable PLL
205 rcc.cr().modify(|w| w.set_pllon(true));
206 rcc.cr().write(|w| w.set_hsion(false));
207 // while !rcc.cr().read().pllrdy() {}
208
209 // configure SYSCLK mux to use PLL clocl
210 rcc.cfgr().modify(|w| w.set_sw(0b11));
211
212 // configure CPU1 & CPU2 dividers
213 rcc.cfgr().modify(|w| w.set_hpre(0)); // not divided
214 rcc.extcfgr().modify(|w| {
215 w.set_c2hpre(0b1000); // div2
216 w.set_shdhpre(0); // not divided
217 });
218
219 // apply APB1 / APB2 values
220 rcc.cfgr().modify(|w| {
221 w.set_ppre1(0b000); // not divided
222 w.set_ppre2(0b000); // not divided
223 });
224
225 // TODO: required
172 // set RF wake-up clock = LSE 226 // set RF wake-up clock = LSE
173 rcc.csr().modify(|w| w.set_rfwkpsel(0b01)); 227 rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
228
229 // set LPTIM1 & LPTIM2 clock source
230 rcc.ccipr().modify(|w| {
231 w.set_lptim1sel(0b00); // PCLK
232 w.set_lptim2sel(0b00); // PCLK
233 });
174} 234}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index f4ec0a80d..6fde61c06 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -41,6 +41,8 @@ pub mod crc;
41pub mod flash; 41pub mod flash;
42#[cfg(all(spi_v1, rcc_f4))] 42#[cfg(all(spi_v1, rcc_f4))]
43pub mod i2s; 43pub mod i2s;
44#[cfg(stm32wb)]
45pub mod ipcc;
44pub mod pwm; 46pub mod pwm;
45#[cfg(quadspi)] 47#[cfg(quadspi)]
46pub mod qspi; 48pub mod qspi;
@@ -52,8 +54,6 @@ pub mod rtc;
52pub mod sdmmc; 54pub mod sdmmc;
53#[cfg(spi)] 55#[cfg(spi)]
54pub mod spi; 56pub mod spi;
55#[cfg(stm32wb)]
56pub mod tl_mbox;
57#[cfg(usart)] 57#[cfg(usart)]
58pub mod usart; 58pub mod usart;
59#[cfg(usb)] 59#[cfg(usb)]
diff --git a/embassy-stm32/src/tl_mbox/cmd.rs b/embassy-stm32/src/tl_mbox/cmd.rs
deleted file mode 100644
index 3507c3231..000000000
--- a/embassy-stm32/src/tl_mbox/cmd.rs
+++ /dev/null
@@ -1,49 +0,0 @@
1use super::PacketHeader;
2
3#[repr(C, packed)]
4#[derive(Copy, Clone)]
5pub struct Cmd {
6 pub cmd_code: u16,
7 pub payload_len: u8,
8 pub payload: [u8; 255],
9}
10
11impl Default for Cmd {
12 fn default() -> Self {
13 Self {
14 cmd_code: 0,
15 payload_len: 0,
16 payload: [0u8; 255],
17 }
18 }
19}
20
21#[repr(C, packed)]
22#[derive(Copy, Clone, Default)]
23pub struct CmdSerial {
24 pub ty: u8,
25 pub cmd: Cmd,
26}
27
28#[repr(C, packed)]
29#[derive(Copy, Clone, Default)]
30pub struct CmdPacket {
31 pub header: PacketHeader,
32 pub cmd_serial: CmdSerial,
33}
34
35#[repr(C, packed)]
36#[derive(Copy, Clone)]
37pub struct AclDataSerial {
38 pub ty: u8,
39 pub handle: u16,
40 pub length: u16,
41 pub acl_data: [u8; 1],
42}
43
44#[repr(C, packed)]
45#[derive(Copy, Clone)]
46pub struct AclDataPacket {
47 pub header: PacketHeader,
48 pub acl_data_serial: AclDataSerial,
49}
diff --git a/embassy-stm32/src/tl_mbox/mm.rs b/embassy-stm32/src/tl_mbox/mm.rs
deleted file mode 100644
index e28a6aa0c..000000000
--- a/embassy-stm32/src/tl_mbox/mm.rs
+++ /dev/null
@@ -1,67 +0,0 @@
1use super::evt::EvtPacket;
2use super::unsafe_linked_list::LinkedListNode;
3use super::{
4 channels, MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE,
5 SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE, TL_REF_TABLE,
6};
7use crate::tl_mbox::ipcc::Ipcc;
8
9pub struct MemoryManager;
10
11impl MemoryManager {
12 pub fn enable() {
13 unsafe {
14 LinkedListNode::init_head(FREE_BUFF_QUEUE.as_mut_ptr());
15 LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
16
17 TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable {
18 spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
19 spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
20 ble_pool: EVT_POOL.as_ptr().cast(),
21 ble_pool_size: POOL_SIZE as u32,
22 pevt_free_buffer_queue: FREE_BUFF_QUEUE.as_mut_ptr(),
23 traces_evt_pool: core::ptr::null(),
24 traces_pool_size: 0,
25 });
26 }
27 }
28
29 pub fn evt_handler() {
30 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false);
31 Self::send_free_buf();
32 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
33 }
34
35 pub fn evt_drop(evt: *mut EvtPacket) {
36 unsafe {
37 let list_node = evt.cast();
38
39 LinkedListNode::remove_tail(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), list_node);
40 }
41
42 let channel_is_busy = Ipcc::c1_is_active_flag(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
43
44 // postpone event buffer freeing to IPCC interrupt handler
45 if channel_is_busy {
46 Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, true);
47 } else {
48 Self::send_free_buf();
49 Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
50 }
51 }
52
53 fn send_free_buf() {
54 unsafe {
55 let mut node_ptr = core::ptr::null_mut();
56 let node_ptr_ptr: *mut _ = &mut node_ptr;
57
58 while !LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
59 LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), node_ptr_ptr);
60 LinkedListNode::insert_tail(
61 (*(*TL_REF_TABLE.as_ptr()).mem_manager_table).pevt_free_buffer_queue,
62 node_ptr,
63 );
64 }
65 }
66 }
67}
diff --git a/embassy-stm32/src/tl_mbox/mod.rs b/embassy-stm32/src/tl_mbox/mod.rs
deleted file mode 100644
index d39c78b2c..000000000
--- a/embassy-stm32/src/tl_mbox/mod.rs
+++ /dev/null
@@ -1,417 +0,0 @@
1use core::mem::MaybeUninit;
2
3use atomic_polyfill::{compiler_fence, Ordering};
4use bit_field::BitField;
5use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_sync::channel::Channel;
8
9use self::ble::Ble;
10use self::cmd::{AclDataPacket, CmdPacket};
11use self::evt::{CsEvt, EvtBox};
12use self::mm::MemoryManager;
13use self::shci::{shci_ble_init, ShciBleInitCmdParam};
14use self::sys::Sys;
15use self::unsafe_linked_list::LinkedListNode;
16use crate::interrupt;
17use crate::interrupt::InterruptExt;
18use crate::peripherals::IPCC;
19pub use crate::tl_mbox::ipcc::Config;
20use crate::tl_mbox::ipcc::Ipcc;
21
22mod ble;
23mod channels;
24mod cmd;
25mod consts;
26mod evt;
27mod ipcc;
28mod mm;
29mod shci;
30mod sys;
31mod unsafe_linked_list;
32
33pub type PacketHeader = LinkedListNode;
34
35const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::<PacketHeader>();
36const TL_EVT_HEADER_SIZE: usize = 3;
37const TL_CS_EVT_SIZE: usize = core::mem::size_of::<CsEvt>();
38
39const CFG_TL_BLE_EVT_QUEUE_LENGTH: usize = 5;
40const CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255;
41const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE;
42
43const POOL_SIZE: usize = CFG_TL_BLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4);
44
45const fn divc(x: usize, y: usize) -> usize {
46 (x + y - 1) / y
47}
48
49#[repr(C, packed)]
50#[derive(Copy, Clone)]
51pub struct SafeBootInfoTable {
52 version: u32,
53}
54
55#[repr(C, packed)]
56#[derive(Copy, Clone)]
57pub struct FusInfoTable {
58 version: u32,
59 memory_size: u32,
60 fus_info: u32,
61}
62
63/// Interrupt handler.
64pub struct ReceiveInterruptHandler {}
65
66impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for ReceiveInterruptHandler {
67 unsafe fn on_interrupt() {
68 // info!("ipcc rx interrupt");
69
70 if Ipcc::is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) {
71 sys::Sys::evt_handler();
72 } else if Ipcc::is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) {
73 ble::Ble::evt_handler();
74 } else {
75 todo!()
76 }
77 }
78}
79
80pub struct TransmitInterruptHandler {}
81
82impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
83 unsafe fn on_interrupt() {
84 // info!("ipcc tx interrupt");
85
86 if Ipcc::is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) {
87 // TODO: handle this case
88 let _ = sys::Sys::cmd_evt_handler();
89 } else if Ipcc::is_tx_pending(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL) {
90 mm::MemoryManager::evt_handler();
91 } else {
92 todo!()
93 }
94 }
95}
96
97/// # Version
98/// - 0 -> 3 = Build - 0: Untracked - 15:Released - x: Tracked version
99/// - 4 -> 7 = branch - 0: Mass Market - x: ...
100/// - 8 -> 15 = Subversion
101/// - 16 -> 23 = Version minor
102/// - 24 -> 31 = Version major
103/// # Memory Size
104/// - 0 -> 7 = Flash ( Number of 4k sector)
105/// - 8 -> 15 = Reserved ( Shall be set to 0 - may be used as flash extension )
106/// - 16 -> 23 = SRAM2b ( Number of 1k sector)
107/// - 24 -> 31 = SRAM2a ( Number of 1k sector)
108#[repr(C, packed)]
109#[derive(Copy, Clone)]
110pub struct WirelessFwInfoTable {
111 version: u32,
112 memory_size: u32,
113 info_stack: u32,
114 reserved: u32,
115}
116
117impl WirelessFwInfoTable {
118 pub fn version_major(&self) -> u8 {
119 let version = self.version;
120 (version.get_bits(24..31) & 0xff) as u8
121 }
122
123 pub fn version_minor(&self) -> u8 {
124 let version = self.version;
125 (version.get_bits(16..23) & 0xff) as u8
126 }
127
128 pub fn subversion(&self) -> u8 {
129 let version = self.version;
130 (version.get_bits(8..15) & 0xff) as u8
131 }
132
133 /// size of FLASH, expressed in number of 4K sectors
134 pub fn flash_size(&self) -> u8 {
135 let memory_size = self.memory_size;
136 (memory_size.get_bits(0..7) & 0xff) as u8
137 }
138
139 /// size for SRAM2a, expressed in number of 1K sectors
140 pub fn sram2a_size(&self) -> u8 {
141 let memory_size = self.memory_size;
142 (memory_size.get_bits(24..31) & 0xff) as u8
143 }
144
145 /// size of SRAM2b, expressed in number of 1K sectors
146 pub fn sram2b_size(&self) -> u8 {
147 let memory_size = self.memory_size;
148 (memory_size.get_bits(16..23) & 0xff) as u8
149 }
150}
151
152#[repr(C, packed)]
153#[derive(Copy, Clone)]
154pub struct DeviceInfoTable {
155 pub safe_boot_info_table: SafeBootInfoTable,
156 pub fus_info_table: FusInfoTable,
157 pub wireless_fw_info_table: WirelessFwInfoTable,
158}
159
160#[repr(C, packed)]
161struct BleTable {
162 pcmd_buffer: *mut CmdPacket,
163 pcs_buffer: *const u8,
164 pevt_queue: *const u8,
165 phci_acl_data_buffer: *mut AclDataPacket,
166}
167
168#[repr(C, packed)]
169struct ThreadTable {
170 no_stack_buffer: *const u8,
171 cli_cmd_rsp_buffer: *const u8,
172 ot_cmd_rsp_buffer: *const u8,
173}
174
175#[repr(C, packed)]
176struct SysTable {
177 pcmd_buffer: *mut CmdPacket,
178 sys_queue: *const LinkedListNode,
179}
180
181#[allow(dead_code)] // Not used currently but reserved
182#[repr(C, packed)]
183struct LldTestTable {
184 cli_cmd_rsp_buffer: *const u8,
185 m0_cmd_buffer: *const u8,
186}
187
188#[allow(dead_code)] // Not used currently but reserved
189#[repr(C, packed)]
190struct BleLldTable {
191 cmd_rsp_buffer: *const u8,
192 m0_cmd_buffer: *const u8,
193}
194
195#[allow(dead_code)] // Not used currently but reserved
196#[repr(C, packed)]
197struct ZigbeeTable {
198 notif_m0_to_m4_buffer: *const u8,
199 appli_cmd_m4_to_m0_buffer: *const u8,
200 request_m0_to_m4_buffer: *const u8,
201}
202
203#[repr(C, packed)]
204struct MemManagerTable {
205 spare_ble_buffer: *const u8,
206 spare_sys_buffer: *const u8,
207
208 ble_pool: *const u8,
209 ble_pool_size: u32,
210
211 pevt_free_buffer_queue: *mut LinkedListNode,
212
213 traces_evt_pool: *const u8,
214 traces_pool_size: u32,
215}
216
217#[repr(C, packed)]
218struct TracesTable {
219 traces_queue: *const u8,
220}
221
222#[repr(C, packed)]
223struct Mac802_15_4Table {
224 pcmd_rsp_buffer: *const u8,
225 pnotack_buffer: *const u8,
226 evt_queue: *const u8,
227}
228
229/// reference table. Contains pointers to all other tables
230#[repr(C, packed)]
231#[derive(Copy, Clone)]
232pub struct RefTable {
233 pub device_info_table: *const DeviceInfoTable,
234 ble_table: *const BleTable,
235 thread_table: *const ThreadTable,
236 sys_table: *const SysTable,
237 mem_manager_table: *const MemManagerTable,
238 traces_table: *const TracesTable,
239 mac_802_15_4_table: *const Mac802_15_4Table,
240 zigbee_table: *const ZigbeeTable,
241 lld_tests_table: *const LldTestTable,
242 ble_lld_table: *const BleLldTable,
243}
244
245#[link_section = "TL_REF_TABLE"]
246pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
247
248#[link_section = "MB_MEM1"]
249static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit();
250
251#[link_section = "MB_MEM1"]
252static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit();
253
254#[link_section = "MB_MEM1"]
255static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit();
256
257#[link_section = "MB_MEM1"]
258static mut TL_LLD_TESTS_TABLE: MaybeUninit<LldTestTable> = MaybeUninit::uninit();
259
260#[link_section = "MB_MEM1"]
261static mut TL_BLE_LLD_TABLE: MaybeUninit<BleLldTable> = MaybeUninit::uninit();
262
263#[link_section = "MB_MEM1"]
264static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit();
265
266#[link_section = "MB_MEM1"]
267static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit();
268
269#[link_section = "MB_MEM1"]
270static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit();
271
272#[link_section = "MB_MEM1"]
273static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit();
274
275#[link_section = "MB_MEM1"]
276static mut TL_ZIGBEE_TABLE: MaybeUninit<ZigbeeTable> = MaybeUninit::uninit();
277
278#[allow(dead_code)] // Not used currently but reserved
279#[link_section = "MB_MEM1"]
280static mut FREE_BUFF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
281
282// not in shared RAM
283static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
284
285#[link_section = "MB_MEM2"]
286static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> =
287 MaybeUninit::uninit();
288
289#[link_section = "MB_MEM2"]
290static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
291
292#[link_section = "MB_MEM2"]
293static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
294
295#[link_section = "MB_MEM2"]
296static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
297
298#[link_section = "MB_MEM2"]
299static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit();
300
301#[link_section = "MB_MEM2"]
302static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
303 MaybeUninit::uninit();
304
305#[link_section = "MB_MEM2"]
306static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
307 MaybeUninit::uninit();
308
309#[link_section = "MB_MEM2"]
310static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
311
312#[link_section = "MB_MEM2"]
313// "magic" numbers from ST ---v---v
314static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit();
315
316// TODO: get a better size, this is a placeholder
317pub(crate) static TL_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 5> = Channel::new();
318
319pub struct TlMbox<'d> {
320 _ipcc: PeripheralRef<'d, IPCC>,
321}
322
323impl<'d> TlMbox<'d> {
324 /// initializes low-level transport between CPU1 and BLE stack on CPU2
325 pub fn new(
326 ipcc: impl Peripheral<P = IPCC> + 'd,
327 _irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler>
328 + interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>,
329 config: Config,
330 ) -> Self {
331 into_ref!(ipcc);
332
333 unsafe {
334 compiler_fence(Ordering::AcqRel);
335
336 TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable {
337 device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
338 ble_table: TL_BLE_TABLE.as_ptr(),
339 thread_table: TL_THREAD_TABLE.as_ptr(),
340 sys_table: TL_SYS_TABLE.as_ptr(),
341 mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
342 traces_table: TL_TRACES_TABLE.as_ptr(),
343 mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(),
344 zigbee_table: TL_ZIGBEE_TABLE.as_ptr(),
345 lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(),
346 ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(),
347 });
348
349 // info!("TL_REF_TABLE addr: {:x}", TL_REF_TABLE.as_ptr() as usize);
350
351 compiler_fence(Ordering::AcqRel);
352
353 TL_SYS_TABLE = MaybeUninit::zeroed();
354 TL_DEVICE_INFO_TABLE = MaybeUninit::zeroed();
355 TL_BLE_TABLE = MaybeUninit::zeroed();
356 TL_THREAD_TABLE = MaybeUninit::zeroed();
357 TL_MEM_MANAGER_TABLE = MaybeUninit::zeroed();
358 TL_TRACES_TABLE = MaybeUninit::zeroed();
359 TL_MAC_802_15_4_TABLE = MaybeUninit::zeroed();
360 TL_ZIGBEE_TABLE = MaybeUninit::zeroed();
361 TL_LLD_TESTS_TABLE = MaybeUninit::zeroed();
362 TL_BLE_LLD_TABLE = MaybeUninit::zeroed();
363
364 EVT_POOL = MaybeUninit::zeroed();
365 SYS_SPARE_EVT_BUF = MaybeUninit::zeroed();
366 BLE_SPARE_EVT_BUF = MaybeUninit::zeroed();
367
368 CS_BUFFER = MaybeUninit::zeroed();
369 BLE_CMD_BUFFER = MaybeUninit::zeroed();
370 HCI_ACL_DATA_BUFFER = MaybeUninit::zeroed();
371
372 compiler_fence(Ordering::AcqRel);
373 }
374
375 Ipcc::enable(config);
376
377 Sys::enable();
378 Ble::enable();
379 MemoryManager::enable();
380
381 // enable interrupts
382 crate::interrupt::IPCC_C1_RX.unpend();
383 crate::interrupt::IPCC_C1_TX.unpend();
384
385 unsafe { crate::interrupt::IPCC_C1_RX.enable() };
386 unsafe { crate::interrupt::IPCC_C1_TX.enable() };
387
388 Self { _ipcc: ipcc }
389 }
390
391 pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> {
392 let info = unsafe { &(*(*TL_REF_TABLE.as_ptr()).device_info_table).wireless_fw_info_table };
393
394 // zero version indicates that CPU2 wasn't active and didn't fill the information table
395 if info.version != 0 {
396 Some(*info)
397 } else {
398 None
399 }
400 }
401
402 pub fn shci_ble_init(&self, param: ShciBleInitCmdParam) {
403 shci_ble_init(param);
404 }
405
406 pub fn send_ble_cmd(&self, buf: &[u8]) {
407 ble::Ble::send_cmd(buf);
408 }
409
410 // pub fn send_sys_cmd(&self, buf: &[u8]) {
411 // sys::Sys::send_cmd(buf);
412 // }
413
414 pub async fn read(&self) -> EvtBox {
415 TL_CHANNEL.recv().await
416 }
417}
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index 14897b171..83a443754 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -9,6 +9,7 @@ embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["de
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] }
12embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
12 13
13defmt = "0.3" 14defmt = "0.3"
14defmt-rtt = "0.4" 15defmt-rtt = "0.4"
diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs
index 8f4e70af0..ae36a7e79 100644
--- a/examples/stm32wb/src/bin/tl_mbox.rs
+++ b/examples/stm32wb/src/bin/tl_mbox.rs
@@ -4,14 +4,15 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::tl_mbox::{Config, TlMbox}; 7use embassy_stm32::bind_interrupts;
8use embassy_stm32::{bind_interrupts, tl_mbox}; 8use embassy_stm32::ipcc::Config;
9use embassy_stm32_wpan::TlMbox;
9use embassy_time::{Duration, Timer}; 10use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
11 12
12bind_interrupts!(struct Irqs{ 13bind_interrupts!(struct Irqs{
13 IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; 14 IPCC_C1_RX => embassy_stm32_wpan::ReceiveInterruptHandler;
14 IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; 15 IPCC_C1_TX => embassy_stm32_wpan::TransmitInterruptHandler;
15}); 16});
16 17
17#[embassy_executor::main] 18#[embassy_executor::main]
@@ -44,7 +45,7 @@ async fn main(_spawner: Spawner) {
44 info!("Hello World!"); 45 info!("Hello World!");
45 46
46 let config = Config::default(); 47 let config = Config::default();
47 let mbox = TlMbox::new(p.IPCC, Irqs, config); 48 let mbox = TlMbox::init(p.IPCC, Irqs, config);
48 49
49 loop { 50 loop {
50 let wireless_fw_info = mbox.wireless_fw_info(); 51 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
index 1724d946f..3132ab3e4 100644
--- a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs
@@ -4,13 +4,15 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::tl_mbox::{Config, TlMbox}; 7use embassy_stm32::bind_interrupts;
8use embassy_stm32::{bind_interrupts, tl_mbox}; 8use embassy_stm32::ipcc::Config;
9use embassy_stm32_wpan::rc::RadioCoprocessor;
10use embassy_stm32_wpan::TlMbox;
9use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
10 12
11bind_interrupts!(struct Irqs{ 13bind_interrupts!(struct Irqs{
12 IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; 14 IPCC_C1_RX => embassy_stm32_wpan::ReceiveInterruptHandler;
13 IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; 15 IPCC_C1_TX => embassy_stm32_wpan::TransmitInterruptHandler;
14}); 16});
15 17
16#[embassy_executor::main] 18#[embassy_executor::main]
@@ -43,55 +45,16 @@ async fn main(_spawner: Spawner) {
43 info!("Hello World!"); 45 info!("Hello World!");
44 46
45 let config = Config::default(); 47 let config = Config::default();
46 let mbox = TlMbox::new(p.IPCC, Irqs, config); 48 let mbox = TlMbox::init(p.IPCC, Irqs, config);
47 49
48 info!("waiting for coprocessor to boot"); 50 let mut rc = RadioCoprocessor::new(mbox);
49 let event_box = mbox.read().await;
50 51
51 let mut payload = [0u8; 6]; 52 let response = rc.read().await;
52 event_box.copy_into_slice(&mut payload).unwrap(); 53 info!("coprocessor ready {}", response);
53 54
54 let event_packet = event_box.evt(); 55 rc.write(&[0x01, 0x03, 0x0c, 0x00, 0x00]);
55 let kind = event_packet.evt_serial.kind; 56 let response = rc.read().await;
56 57 info!("ble reset rsp {}", response);
57 // means recieved SYS event, which indicates in this case that the coprocessor is ready
58 if kind == 0x12 {
59 let code = event_packet.evt_serial.evt.evt_code;
60 let payload_len = event_packet.evt_serial.evt.payload_len;
61
62 info!(
63 "==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}",
64 kind,
65 code,
66 payload_len,
67 payload[3..]
68 );
69 }
70
71 // initialize ble stack, does not return a response
72 mbox.shci_ble_init(Default::default());
73
74 info!("resetting BLE");
75 mbox.send_ble_cmd(&[0x01, 0x03, 0x0c, 0x00, 0x00]);
76
77 let event_box = mbox.read().await;
78
79 let mut payload = [0u8; 7];
80 event_box.copy_into_slice(&mut payload).unwrap();
81
82 let event_packet = event_box.evt();
83 let kind = event_packet.evt_serial.kind;
84
85 let code = event_packet.evt_serial.evt.evt_code;
86 let payload_len = event_packet.evt_serial.evt.payload_len;
87
88 info!(
89 "==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}",
90 kind,
91 code,
92 payload_len,
93 payload[3..]
94 );
95 58
96 info!("Test OK"); 59 info!("Test OK");
97 cortex_m::asm::bkpt(); 60 cortex_m::asm::bkpt();
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 3f48bf3f1..db97e929b 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -12,7 +12,7 @@ stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma"] # Nucleo
12stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo 12stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo
13stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo 13stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo
14stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo 14stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo
15stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble"] # Nucleo 15stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble", "dep:embassy-stm32-wpan"] # Nucleo
16stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo 16stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo
17stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board 17stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board
18 18
@@ -29,6 +29,7 @@ embassy-executor = { version = "0.2.0", path = "../../embassy-executor", feature
29embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] } 29embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] }
30embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] } 30embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] }
31embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 31embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
32embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg"] }
32 33
33defmt = "0.3.0" 34defmt = "0.3.0"
34defmt-rtt = "0.4" 35defmt-rtt = "0.4"
diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs
index fab9f0e1b..0f643d578 100644
--- a/tests/stm32/src/bin/tl_mbox.rs
+++ b/tests/stm32/src/bin/tl_mbox.rs
@@ -8,13 +8,14 @@ mod common;
8 8
9use common::*; 9use common::*;
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_stm32::tl_mbox::{Config, TlMbox}; 11use embassy_stm32::bind_interrupts;
12use embassy_stm32::{bind_interrupts, tl_mbox}; 12use embassy_stm32::ipcc::Config;
13use embassy_stm32_wpan::TlMbox;
13use embassy_time::{Duration, Timer}; 14use embassy_time::{Duration, Timer};
14 15
15bind_interrupts!(struct Irqs{ 16bind_interrupts!(struct Irqs{
16 IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; 17 IPCC_C1_RX => embassy_stm32_wpan::ReceiveInterruptHandler;
17 IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; 18 IPCC_C1_TX => embassy_stm32_wpan::TransmitInterruptHandler;
18}); 19});
19 20
20#[embassy_executor::main] 21#[embassy_executor::main]
@@ -23,7 +24,7 @@ async fn main(_spawner: Spawner) {
23 info!("Hello World!"); 24 info!("Hello World!");
24 25
25 let config = Config::default(); 26 let config = Config::default();
26 let mbox = TlMbox::new(p.IPCC, Irqs, config); 27 let mbox = TlMbox::init(p.IPCC, Irqs, config);
27 28
28 loop { 29 loop {
29 let wireless_fw_info = mbox.wireless_fw_info(); 30 let wireless_fw_info = mbox.wireless_fw_info();