commit
0053a8a1a7
39
embassy-stm32-wpan/Cargo.toml
Normal file
39
embassy-stm32-wpan/Cargo.toml
Normal file
@ -0,0 +1,39 @@
|
||||
[package]
|
||||
name = "embassy-stm32-wpan"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
|
||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
||||
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" }
|
||||
embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
cortex-m = "0.7.6"
|
||||
heapless = "0.7.16"
|
||||
|
||||
bit_field = "0.10.2"
|
||||
|
||||
[features]
|
||||
defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"]
|
||||
|
||||
stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
|
||||
stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]
|
||||
stm32wb30ce = [ "embassy-stm32/stm32wb30ce" ]
|
||||
stm32wb35cc = [ "embassy-stm32/stm32wb35cc" ]
|
||||
stm32wb35ce = [ "embassy-stm32/stm32wb35ce" ]
|
||||
stm32wb50cg = [ "embassy-stm32/stm32wb50cg" ]
|
||||
stm32wb55cc = [ "embassy-stm32/stm32wb55cc" ]
|
||||
stm32wb55ce = [ "embassy-stm32/stm32wb55ce" ]
|
||||
stm32wb55cg = [ "embassy-stm32/stm32wb55cg" ]
|
||||
stm32wb55rc = [ "embassy-stm32/stm32wb55rc" ]
|
||||
stm32wb55re = [ "embassy-stm32/stm32wb55re" ]
|
||||
stm32wb55rg = [ "embassy-stm32/stm32wb55rg" ]
|
||||
stm32wb55vc = [ "embassy-stm32/stm32wb55vc" ]
|
||||
stm32wb55ve = [ "embassy-stm32/stm32wb55ve" ]
|
||||
stm32wb55vg = [ "embassy-stm32/stm32wb55vg" ]
|
||||
stm32wb55vy = [ "embassy-stm32/stm32wb55vy" ]
|
34
embassy-stm32-wpan/build.rs
Normal file
34
embassy-stm32-wpan/build.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
match env::vars()
|
||||
.map(|(a, _)| a)
|
||||
.filter(|x| x.starts_with("CARGO_FEATURE_STM32"))
|
||||
.get_one()
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(GetOneError::None) => panic!("No stm32xx Cargo feature enabled"),
|
||||
Err(GetOneError::Multiple) => panic!("Multiple stm32xx Cargo features enabled"),
|
||||
}
|
||||
}
|
||||
|
||||
enum GetOneError {
|
||||
None,
|
||||
Multiple,
|
||||
}
|
||||
|
||||
trait IteratorExt: Iterator {
|
||||
fn get_one(self) -> Result<Self::Item, GetOneError>;
|
||||
}
|
||||
|
||||
impl<T: Iterator> IteratorExt for T {
|
||||
fn get_one(mut self) -> Result<Self::Item, GetOneError> {
|
||||
match self.next() {
|
||||
None => Err(GetOneError::None),
|
||||
Some(res) => match self.next() {
|
||||
Some(_) => Err(GetOneError::Multiple),
|
||||
None => Ok(res),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +1,26 @@
|
||||
use embassy_futures::block_on;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use super::cmd::CmdSerial;
|
||||
use super::consts::TlPacketType;
|
||||
use super::evt::EvtBox;
|
||||
use super::unsafe_linked_list::LinkedListNode;
|
||||
use super::{
|
||||
channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE, TL_CHANNEL,
|
||||
TL_REF_TABLE,
|
||||
use embassy_stm32::ipcc::Ipcc;
|
||||
|
||||
use crate::cmd::{CmdPacket, CmdSerial};
|
||||
use crate::consts::TlPacketType;
|
||||
use crate::evt::EvtBox;
|
||||
use crate::tables::BleTable;
|
||||
use crate::unsafe_linked_list::LinkedListNode;
|
||||
use crate::{
|
||||
channels, BLE_CMD_BUFFER, CS_BUFFER, EVT_CHANNEL, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE, TL_REF_TABLE,
|
||||
};
|
||||
use crate::tl_mbox::cmd::CmdPacket;
|
||||
use crate::tl_mbox::ipcc::Ipcc;
|
||||
|
||||
pub struct Ble;
|
||||
|
||||
impl Ble {
|
||||
pub fn enable() {
|
||||
pub(super) fn enable() {
|
||||
unsafe {
|
||||
LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
|
||||
|
||||
TL_BLE_TABLE.as_mut_ptr().write_volatile(BleTable {
|
||||
TL_BLE_TABLE = MaybeUninit::new(BleTable {
|
||||
pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(),
|
||||
pcs_buffer: CS_BUFFER.as_mut_ptr().cast(),
|
||||
pcs_buffer: CS_BUFFER.as_ptr().cast(),
|
||||
pevt_queue: EVT_QUEUE.as_ptr().cast(),
|
||||
phci_acl_data_buffer: HCI_ACL_DATA_BUFFER.as_mut_ptr().cast(),
|
||||
});
|
||||
@ -29,7 +29,7 @@ impl Ble {
|
||||
Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, true);
|
||||
}
|
||||
|
||||
pub fn evt_handler() {
|
||||
pub(super) fn evt_handler() {
|
||||
unsafe {
|
||||
let mut node_ptr = core::ptr::null_mut();
|
||||
let node_ptr_ptr: *mut _ = &mut node_ptr;
|
||||
@ -40,25 +40,43 @@ impl Ble {
|
||||
let event = node_ptr.cast();
|
||||
let event = EvtBox::new(event);
|
||||
|
||||
block_on(TL_CHANNEL.send(event));
|
||||
EVT_CHANNEL.try_send(event).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL);
|
||||
}
|
||||
|
||||
pub fn send_cmd(buf: &[u8]) {
|
||||
pub(super) fn acl_data_handler() {
|
||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, false);
|
||||
|
||||
// TODO: ACL data ack to the user
|
||||
}
|
||||
|
||||
pub fn ble_send_cmd(buf: &[u8]) {
|
||||
debug!("writing ble cmd");
|
||||
|
||||
unsafe {
|
||||
let pcmd_buffer: *mut CmdPacket = (*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
|
||||
let pcmd_serial: *mut CmdSerial = &mut (*pcmd_buffer).cmd_serial;
|
||||
let pcmd_serial: *mut CmdSerial = &mut (*pcmd_buffer).cmdserial;
|
||||
let pcmd_serial_buf: *mut u8 = pcmd_serial.cast();
|
||||
|
||||
core::ptr::copy(buf.as_ptr(), pcmd_serial_buf, buf.len());
|
||||
|
||||
let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
|
||||
cmd_packet.cmd_serial.ty = TlPacketType::BleCmd as u8;
|
||||
cmd_packet.cmdserial.ty = TlPacketType::BleCmd as u8;
|
||||
}
|
||||
|
||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL);
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub(super) fn ble_send_acl_data() {
|
||||
let cmd_packet = unsafe { &mut *(*TL_REF_TABLE.assume_init().ble_table).phci_acl_data_buffer };
|
||||
|
||||
cmd_packet.acl_data_serial.ty = TlPacketType::AclData as u8;
|
||||
|
||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL);
|
||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, true);
|
||||
}
|
||||
}
|
@ -50,36 +50,30 @@
|
||||
//!
|
||||
|
||||
pub mod cpu1 {
|
||||
use crate::tl_mbox::ipcc::IpccChannel;
|
||||
use embassy_stm32::ipcc::IpccChannel;
|
||||
|
||||
// Not used currently but reserved
|
||||
pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1;
|
||||
// Not used currently but reserved
|
||||
pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||
// Not used currently but reserved
|
||||
pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4;
|
||||
pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6;
|
||||
}
|
||||
|
||||
pub mod cpu2 {
|
||||
use crate::tl_mbox::ipcc::IpccChannel;
|
||||
use embassy_stm32::ipcc::IpccChannel;
|
||||
|
||||
pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1;
|
||||
pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||
@ -88,10 +82,8 @@ pub mod cpu2 {
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_BLE_LLD_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_BLE_LLDÇM0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||
pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
77
embassy-stm32-wpan/src/cmd.rs
Normal file
77
embassy-stm32-wpan/src/cmd.rs
Normal file
@ -0,0 +1,77 @@
|
||||
use crate::evt::{EvtPacket, EvtSerial};
|
||||
use crate::{PacketHeader, TL_EVT_HEADER_SIZE};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct Cmd {
|
||||
pub cmd_code: u16,
|
||||
pub payload_len: u8,
|
||||
pub payload: [u8; 255],
|
||||
}
|
||||
|
||||
impl Default for Cmd {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
cmd_code: 0,
|
||||
payload_len: 0,
|
||||
payload: [0u8; 255],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
#[repr(C, packed)]
|
||||
pub struct CmdSerial {
|
||||
pub ty: u8,
|
||||
pub cmd: Cmd,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
#[repr(C, packed)]
|
||||
pub struct CmdPacket {
|
||||
pub header: PacketHeader,
|
||||
pub cmdserial: CmdSerial,
|
||||
}
|
||||
|
||||
impl CmdPacket {
|
||||
/// Writes an underlying CmdPacket into the provided buffer.
|
||||
/// Returns a number of bytes that were written.
|
||||
/// Returns an error if event kind is unknown or if provided buffer size is not enough.
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
|
||||
unsafe {
|
||||
let cmd_ptr: *const CmdPacket = self;
|
||||
let self_as_evt_ptr: *const EvtPacket = cmd_ptr.cast();
|
||||
let evt_serial: *const EvtSerial = &(*self_as_evt_ptr).evt_serial;
|
||||
|
||||
let acl_data: *const AclDataPacket = cmd_ptr.cast();
|
||||
let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
|
||||
let acl_serial_buf: *const u8 = acl_serial.cast();
|
||||
|
||||
let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
|
||||
if len > buf.len() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len);
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct AclDataSerial {
|
||||
pub ty: u8,
|
||||
pub handle: u16,
|
||||
pub length: u16,
|
||||
pub acl_data: [u8; 1],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct AclDataPacket {
|
||||
pub header: PacketHeader,
|
||||
pub acl_data_serial: AclDataSerial,
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
#[derive(PartialEq)]
|
||||
use core::convert::TryFrom;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub enum TlPacketType {
|
||||
BleCmd = 0x01,
|
@ -3,9 +3,11 @@ use core::mem::MaybeUninit;
|
||||
use super::cmd::{AclDataPacket, AclDataSerial};
|
||||
use super::consts::TlPacketType;
|
||||
use super::{PacketHeader, TL_EVT_HEADER_SIZE};
|
||||
use crate::tl_mbox::mm::MemoryManager;
|
||||
use crate::mm;
|
||||
|
||||
/// the payload of [`Evt`] for a command status event
|
||||
/**
|
||||
* The payload of `Evt` for a command status event
|
||||
*/
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct CsEvt {
|
||||
@ -14,16 +16,39 @@ pub struct CsEvt {
|
||||
pub cmd_code: u16,
|
||||
}
|
||||
|
||||
/// the payload of [`Evt`] for a command complete event
|
||||
#[derive(Clone, Copy, Default)]
|
||||
/**
|
||||
* The payload of `Evt` for a command complete event
|
||||
*/
|
||||
#[derive(Copy, Clone, Default)]
|
||||
#[repr(C, packed)]
|
||||
pub struct CcEvt {
|
||||
pub num_cmd: u8,
|
||||
pub cmd_code: u8,
|
||||
pub cmd_code: u16,
|
||||
pub payload: [u8; 1],
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
impl CcEvt {
|
||||
pub fn write(&self, buf: &mut [u8]) {
|
||||
unsafe {
|
||||
let len = core::mem::size_of::<CcEvt>();
|
||||
assert!(buf.len() >= len);
|
||||
|
||||
let self_ptr: *const CcEvt = self;
|
||||
let self_buf_ptr: *const u8 = self_ptr.cast();
|
||||
|
||||
core::ptr::copy(self_buf_ptr, buf.as_mut_ptr(), len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
#[repr(C, packed)]
|
||||
pub struct AsynchEvt {
|
||||
sub_evt_code: u16,
|
||||
payload: [u8; 1],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
#[repr(C, packed)]
|
||||
pub struct Evt {
|
||||
pub evt_code: u8,
|
||||
@ -31,7 +56,7 @@ pub struct Evt {
|
||||
pub payload: [u8; 1],
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
#[derive(Copy, Clone, Default)]
|
||||
#[repr(C, packed)]
|
||||
pub struct EvtSerial {
|
||||
pub kind: u8,
|
||||
@ -46,14 +71,26 @@ pub struct EvtSerial {
|
||||
/// Be careful that the asynchronous events reported by the CPU2 on the system channel do
|
||||
/// include the header and shall use `EvtPacket` format. Only the command response format on the
|
||||
/// system channel is different.
|
||||
#[derive(Clone, Copy, Default)]
|
||||
#[derive(Copy, Clone, Default)]
|
||||
#[repr(C, packed)]
|
||||
pub struct EvtPacket {
|
||||
pub header: PacketHeader,
|
||||
pub evt_serial: EvtSerial,
|
||||
}
|
||||
|
||||
/// Smart pointer to the [`EvtPacket`] that will dispose of it automatically on drop
|
||||
impl EvtPacket {
|
||||
pub fn kind(&self) -> u8 {
|
||||
self.evt_serial.kind
|
||||
}
|
||||
|
||||
pub fn evt(&self) -> &Evt {
|
||||
&self.evt_serial.evt
|
||||
}
|
||||
}
|
||||
|
||||
/// smart pointer to the [`EvtPacket`] that will dispose of [`EvtPacket`] buffer automatically
|
||||
/// on [`Drop`]
|
||||
#[derive(Debug)]
|
||||
pub struct EvtBox {
|
||||
ptr: *mut EvtPacket,
|
||||
}
|
||||
@ -64,7 +101,7 @@ impl EvtBox {
|
||||
Self { ptr }
|
||||
}
|
||||
|
||||
/// Copies the event data from inner pointer and returns and event structure
|
||||
/// copies event data from inner pointer and returns an event structure
|
||||
pub fn evt(&self) -> EvtPacket {
|
||||
let mut evt = MaybeUninit::uninit();
|
||||
unsafe {
|
||||
@ -73,28 +110,11 @@ impl EvtBox {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the size of a buffer required to hold this event
|
||||
pub fn size(&self) -> Result<usize, ()> {
|
||||
unsafe {
|
||||
let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
|
||||
|
||||
if evt_kind == TlPacketType::AclData {
|
||||
let acl_data: *const AclDataPacket = self.ptr.cast();
|
||||
let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
|
||||
|
||||
Ok((*acl_serial).length as usize + 5)
|
||||
} else {
|
||||
let evt_data: *const EvtPacket = self.ptr.cast();
|
||||
let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
|
||||
|
||||
Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// writes an underlying [`EvtPacket`] into the provided buffer. Returns the number of bytes that were
|
||||
/// written. Returns an error if event kind is unkown or if provided buffer size is not enough
|
||||
pub fn copy_into_slice(&self, buf: &mut [u8]) -> Result<usize, ()> {
|
||||
/// writes an underlying [`EvtPacket`] into the provided buffer.
|
||||
/// Returns the number of bytes that were written.
|
||||
/// Returns an error if event kind is unknown or if provided buffer size is not enough.
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
|
||||
unsafe {
|
||||
let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
|
||||
|
||||
@ -127,10 +147,30 @@ impl EvtBox {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the size of a buffer required to hold this event
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn size(&self) -> Result<usize, ()> {
|
||||
unsafe {
|
||||
let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
|
||||
|
||||
let evt_data: *const EvtPacket = self.ptr.cast();
|
||||
let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
|
||||
|
||||
let acl_data: *const AclDataPacket = self.ptr.cast();
|
||||
let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
|
||||
|
||||
if let TlPacketType::AclData = evt_kind {
|
||||
Ok((*acl_serial).length as usize + 5)
|
||||
} else {
|
||||
Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for EvtBox {
|
||||
fn drop(&mut self) {
|
||||
MemoryManager::evt_drop(self.ptr);
|
||||
mm::MemoryManager::evt_drop(self.ptr);
|
||||
}
|
||||
}
|
225
embassy-stm32-wpan/src/fmt.rs
Normal file
225
embassy-stm32-wpan/src/fmt.rs
Normal file
@ -0,0 +1,225 @@
|
||||
#![macro_use]
|
||||
#![allow(unused_macros)]
|
||||
|
||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||
|
||||
macro_rules! assert {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::assert!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::assert!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! assert_eq {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::assert_eq!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::assert_eq!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! assert_ne {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::assert_ne!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::assert_ne!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! debug_assert {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::debug_assert!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::debug_assert!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! debug_assert_eq {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::debug_assert_eq!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::debug_assert_eq!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! debug_assert_ne {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::debug_assert_ne!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::debug_assert_ne!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! todo {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::todo!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::todo!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! panic {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::panic!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::panic!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! trace {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::trace!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::trace!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! debug {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::debug!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::debug!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! info {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::info!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::info!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! warn {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::warn!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::warn!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! error {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::error!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::error!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
macro_rules! unwrap {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unwrap!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
macro_rules! unwrap {
|
||||
($arg:expr) => {
|
||||
match $crate::fmt::Try::into_result($arg) {
|
||||
::core::result::Result::Ok(t) => t,
|
||||
::core::result::Result::Err(e) => {
|
||||
::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
($arg:expr, $($msg:expr),+ $(,)? ) => {
|
||||
match $crate::fmt::Try::into_result($arg) {
|
||||
::core::result::Result::Ok(t) => t,
|
||||
::core::result::Result::Err(e) => {
|
||||
::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct NoneError;
|
||||
|
||||
pub trait Try {
|
||||
type Ok;
|
||||
type Error;
|
||||
fn into_result(self) -> Result<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
impl<T> Try for Option<T> {
|
||||
type Ok = T;
|
||||
type Error = NoneError;
|
||||
|
||||
#[inline]
|
||||
fn into_result(self) -> Result<T, NoneError> {
|
||||
self.ok_or(NoneError)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Try for Result<T, E> {
|
||||
type Ok = T;
|
||||
type Error = E;
|
||||
|
||||
#[inline]
|
||||
fn into_result(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
266
embassy-stm32-wpan/src/lib.rs
Normal file
266
embassy-stm32-wpan/src/lib.rs
Normal file
@ -0,0 +1,266 @@
|
||||
#![no_std]
|
||||
|
||||
// This must go FIRST so that all the other modules see its macros.
|
||||
pub mod fmt;
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use cmd::CmdPacket;
|
||||
use embassy_futures::block_on;
|
||||
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
||||
use embassy_stm32::interrupt;
|
||||
use embassy_stm32::interrupt::typelevel::Interrupt;
|
||||
use embassy_stm32::ipcc::{Config, Ipcc};
|
||||
use embassy_stm32::peripherals::IPCC;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::channel::Channel;
|
||||
use embassy_sync::signal::Signal;
|
||||
use evt::{CcEvt, EvtBox};
|
||||
use tables::{
|
||||
BleTable, DeviceInfoTable, Mac802_15_4Table, MemManagerTable, RefTable, SysTable, ThreadTable, TracesTable,
|
||||
WirelessFwInfoTable,
|
||||
};
|
||||
use unsafe_linked_list::LinkedListNode;
|
||||
|
||||
pub mod ble;
|
||||
pub mod channels;
|
||||
pub mod cmd;
|
||||
pub mod consts;
|
||||
pub mod evt;
|
||||
pub mod mm;
|
||||
pub mod rc;
|
||||
pub mod shci;
|
||||
pub mod sys;
|
||||
pub mod tables;
|
||||
pub mod unsafe_linked_list;
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct ReceiveInterruptHandler {}
|
||||
|
||||
impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for ReceiveInterruptHandler {
|
||||
unsafe fn on_interrupt() {
|
||||
if Ipcc::is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) {
|
||||
debug!("RX SYS evt");
|
||||
sys::Sys::evt_handler();
|
||||
} else if Ipcc::is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) {
|
||||
debug!("RX BLE evt");
|
||||
ble::Ble::evt_handler();
|
||||
}
|
||||
|
||||
STATE.signal(());
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TransmitInterruptHandler {}
|
||||
|
||||
impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
|
||||
unsafe fn on_interrupt() {
|
||||
if Ipcc::is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) {
|
||||
debug!("TX SYS cmd rsp");
|
||||
let cc = sys::Sys::cmd_evt_handler();
|
||||
|
||||
LAST_CC_EVT.signal(cc);
|
||||
} else if Ipcc::is_tx_pending(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL) {
|
||||
debug!("TX MM release");
|
||||
mm::MemoryManager::free_buf_handler();
|
||||
} else if Ipcc::is_tx_pending(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL) {
|
||||
debug!("TX HCI acl");
|
||||
ble::Ble::acl_data_handler();
|
||||
}
|
||||
|
||||
STATE.signal(());
|
||||
}
|
||||
}
|
||||
|
||||
#[link_section = "TL_REF_TABLE"]
|
||||
pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||
|
||||
// Not in shared RAM
|
||||
static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut TRACES_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||
|
||||
type PacketHeader = LinkedListNode;
|
||||
|
||||
const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::<PacketHeader>();
|
||||
const TL_EVT_HEADER_SIZE: usize = 3;
|
||||
const TL_CS_EVT_SIZE: usize = core::mem::size_of::<evt::CsEvt>();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> =
|
||||
MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
pub static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
|
||||
|
||||
/**
|
||||
* Queue length of BLE Event
|
||||
* This parameter defines the number of asynchronous events that can be stored in the HCI layer before
|
||||
* being reported to the application. When a command is sent to the BLE core coprocessor, the HCI layer
|
||||
* is waiting for the event with the Num_HCI_Command_Packets set to 1. The receive queue shall be large
|
||||
* enough to store all asynchronous events received in between.
|
||||
* When CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE is set to 27, this allow to store three 255 bytes long asynchronous events
|
||||
* between the HCI command and its event.
|
||||
* This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is to small,
|
||||
* the system may hang if the queue is full with asynchronous events and the HCI layer is still waiting
|
||||
* for a CC/CS event, In that case, the notification TL_BLE_HCI_ToNot() is called to indicate
|
||||
* to the application a HCI command did not receive its command event within 30s (Default HCI Timeout).
|
||||
*/
|
||||
const CFG_TLBLE_EVT_QUEUE_LENGTH: usize = 5;
|
||||
const CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255;
|
||||
const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE;
|
||||
|
||||
const fn divc(x: usize, y: usize) -> usize {
|
||||
((x) + (y) - 1) / (y)
|
||||
}
|
||||
|
||||
const POOL_SIZE: usize = CFG_TLBLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4);
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
|
||||
MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
|
||||
MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
// fuck these "magic" numbers from ST ---v---v
|
||||
static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit();
|
||||
|
||||
/// current event that is produced during IPCC IRQ handler execution
|
||||
/// on SYS channel
|
||||
static EVT_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 32> = Channel::new();
|
||||
|
||||
/// last received Command Complete event
|
||||
static LAST_CC_EVT: Signal<CriticalSectionRawMutex, CcEvt> = Signal::new();
|
||||
|
||||
static STATE: Signal<CriticalSectionRawMutex, ()> = Signal::new();
|
||||
|
||||
pub struct TlMbox<'d> {
|
||||
_ipcc: PeripheralRef<'d, IPCC>,
|
||||
}
|
||||
|
||||
impl<'d> TlMbox<'d> {
|
||||
pub fn init(
|
||||
ipcc: impl Peripheral<P = IPCC> + 'd,
|
||||
_irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler>
|
||||
+ interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(ipcc);
|
||||
|
||||
unsafe {
|
||||
TL_REF_TABLE = MaybeUninit::new(RefTable {
|
||||
device_info_table: TL_DEVICE_INFO_TABLE.as_mut_ptr(),
|
||||
ble_table: TL_BLE_TABLE.as_ptr(),
|
||||
thread_table: TL_THREAD_TABLE.as_ptr(),
|
||||
sys_table: TL_SYS_TABLE.as_ptr(),
|
||||
mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
|
||||
traces_table: TL_TRACES_TABLE.as_ptr(),
|
||||
mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(),
|
||||
});
|
||||
|
||||
TL_SYS_TABLE = MaybeUninit::zeroed();
|
||||
TL_DEVICE_INFO_TABLE = MaybeUninit::zeroed();
|
||||
TL_BLE_TABLE = MaybeUninit::zeroed();
|
||||
TL_THREAD_TABLE = MaybeUninit::zeroed();
|
||||
TL_MEM_MANAGER_TABLE = MaybeUninit::zeroed();
|
||||
TL_TRACES_TABLE = MaybeUninit::zeroed();
|
||||
TL_MAC_802_15_4_TABLE = MaybeUninit::zeroed();
|
||||
|
||||
EVT_POOL = MaybeUninit::zeroed();
|
||||
SYS_SPARE_EVT_BUF = MaybeUninit::zeroed();
|
||||
BLE_SPARE_EVT_BUF = MaybeUninit::zeroed();
|
||||
|
||||
CS_BUFFER = MaybeUninit::zeroed();
|
||||
BLE_CMD_BUFFER = MaybeUninit::zeroed();
|
||||
HCI_ACL_DATA_BUFFER = MaybeUninit::zeroed();
|
||||
}
|
||||
|
||||
Ipcc::enable(config);
|
||||
|
||||
sys::Sys::enable();
|
||||
ble::Ble::enable();
|
||||
mm::MemoryManager::enable();
|
||||
|
||||
// enable interrupts
|
||||
interrupt::typelevel::IPCC_C1_RX::unpend();
|
||||
interrupt::typelevel::IPCC_C1_TX::unpend();
|
||||
|
||||
unsafe { interrupt::typelevel::IPCC_C1_RX::enable() };
|
||||
unsafe { interrupt::typelevel::IPCC_C1_TX::enable() };
|
||||
|
||||
STATE.reset();
|
||||
|
||||
Self { _ipcc: ipcc }
|
||||
}
|
||||
|
||||
/// Returns CPU2 wireless firmware information (if present).
|
||||
pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> {
|
||||
let info = unsafe { &(*(*TL_REF_TABLE.as_ptr()).device_info_table).wireless_fw_info_table };
|
||||
|
||||
// Zero version indicates that CPU2 wasn't active and didn't fill the information table
|
||||
if info.version != 0 {
|
||||
Some(*info)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// picks single [`EvtBox`] from internal event queue.
|
||||
///
|
||||
/// Internal event queu is populated in IPCC_RX_IRQ handler
|
||||
pub fn dequeue_event(&mut self) -> Option<EvtBox> {
|
||||
EVT_CHANNEL.try_recv().ok()
|
||||
}
|
||||
|
||||
/// retrieves last Command Complete event and removes it from mailbox
|
||||
pub fn pop_last_cc_evt(&mut self) -> Option<CcEvt> {
|
||||
if LAST_CC_EVT.signaled() {
|
||||
let cc = block_on(LAST_CC_EVT.wait());
|
||||
LAST_CC_EVT.reset();
|
||||
Some(cc)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
75
embassy-stm32-wpan/src/mm.rs
Normal file
75
embassy-stm32-wpan/src/mm.rs
Normal file
@ -0,0 +1,75 @@
|
||||
//! Memory manager routines
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use embassy_stm32::ipcc::Ipcc;
|
||||
|
||||
use crate::evt::EvtPacket;
|
||||
use crate::tables::MemManagerTable;
|
||||
use crate::unsafe_linked_list::LinkedListNode;
|
||||
use crate::{
|
||||
channels, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, SYS_SPARE_EVT_BUF,
|
||||
TL_MEM_MANAGER_TABLE, TL_REF_TABLE,
|
||||
};
|
||||
|
||||
pub(super) struct MemoryManager;
|
||||
|
||||
impl MemoryManager {
|
||||
pub fn enable() {
|
||||
unsafe {
|
||||
LinkedListNode::init_head(FREE_BUF_QUEUE.as_mut_ptr());
|
||||
LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
|
||||
|
||||
TL_MEM_MANAGER_TABLE = MaybeUninit::new(MemManagerTable {
|
||||
spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
|
||||
spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
|
||||
blepool: EVT_POOL.as_ptr().cast(),
|
||||
blepoolsize: POOL_SIZE as u32,
|
||||
pevt_free_buffer_queue: FREE_BUF_QUEUE.as_mut_ptr(),
|
||||
traces_evt_pool: core::ptr::null(),
|
||||
tracespoolsize: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn evt_drop(evt: *mut EvtPacket) {
|
||||
unsafe {
|
||||
let list_node = evt.cast();
|
||||
|
||||
LinkedListNode::insert_tail(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), list_node);
|
||||
|
||||
let channel_is_busy = Ipcc::c1_is_active_flag(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
|
||||
|
||||
// postpone event buffer freeing to IPCC interrupt handler
|
||||
if channel_is_busy {
|
||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, true);
|
||||
} else {
|
||||
Self::send_free_buf();
|
||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// gives free event buffers back to CPU2 from local buffer queue
|
||||
pub fn send_free_buf() {
|
||||
unsafe {
|
||||
let mut node_ptr = core::ptr::null_mut();
|
||||
let node_ptr_ptr: *mut _ = &mut node_ptr;
|
||||
|
||||
while !LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
|
||||
LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), node_ptr_ptr);
|
||||
LinkedListNode::insert_tail(
|
||||
(*(*TL_REF_TABLE.as_ptr()).mem_manager_table).pevt_free_buffer_queue,
|
||||
node_ptr,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// free buffer channel interrupt handler
|
||||
pub fn free_buf_handler() {
|
||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false);
|
||||
Self::send_free_buf();
|
||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
|
||||
}
|
||||
}
|
50
embassy-stm32-wpan/src/rc.rs
Normal file
50
embassy-stm32-wpan/src/rc.rs
Normal file
@ -0,0 +1,50 @@
|
||||
use crate::ble::Ble;
|
||||
use crate::consts::TlPacketType;
|
||||
use crate::{shci, TlMbox, STATE};
|
||||
|
||||
pub struct RadioCoprocessor<'d> {
|
||||
mbox: TlMbox<'d>,
|
||||
rx_buf: [u8; 500],
|
||||
}
|
||||
|
||||
impl<'d> RadioCoprocessor<'d> {
|
||||
pub fn new(mbox: TlMbox<'d>) -> Self {
|
||||
Self {
|
||||
mbox,
|
||||
rx_buf: [0u8; 500],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) {
|
||||
let cmd_code = buf[0];
|
||||
let cmd = TlPacketType::try_from(cmd_code).unwrap();
|
||||
|
||||
match &cmd {
|
||||
TlPacketType::BleCmd => Ble::ble_send_cmd(buf),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read(&mut self) -> &[u8] {
|
||||
loop {
|
||||
STATE.wait().await;
|
||||
|
||||
while let Some(evt) = self.mbox.dequeue_event() {
|
||||
let event = evt.evt();
|
||||
|
||||
evt.write(&mut self.rx_buf).unwrap();
|
||||
|
||||
if event.kind() == 18 {
|
||||
shci::shci_ble_init(Default::default());
|
||||
self.rx_buf[0] = 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if self.mbox.pop_last_cc_evt().is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
return &self.rx_buf;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +1,10 @@
|
||||
//! HCI commands for system channel
|
||||
|
||||
use super::cmd::CmdPacket;
|
||||
use super::consts::TlPacketType;
|
||||
use super::{channels, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE, TL_SYS_TABLE};
|
||||
use crate::tl_mbox::ipcc::Ipcc;
|
||||
use super::{sys, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE, TL_SYS_TABLE};
|
||||
|
||||
const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66;
|
||||
pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
|
||||
#[allow(dead_code)]
|
||||
const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C, packed)]
|
||||
pub struct ShciBleInitCmdParam {
|
||||
/// NOT USED CURRENTLY
|
||||
@ -63,39 +57,44 @@ impl Default for ShciBleInitCmdParam {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
#[repr(C, packed)]
|
||||
pub struct ShciHeader {
|
||||
metadata: [u32; 3],
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C, packed)]
|
||||
pub struct ShciBleInitCmdPacket {
|
||||
header: ShciHeader,
|
||||
param: ShciBleInitCmdParam,
|
||||
}
|
||||
|
||||
pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
|
||||
|
||||
pub fn shci_ble_init(param: ShciBleInitCmdParam) {
|
||||
debug!("sending SHCI");
|
||||
|
||||
let mut packet = ShciBleInitCmdPacket {
|
||||
header: ShciHeader::default(),
|
||||
param,
|
||||
};
|
||||
|
||||
let packet_ptr: *mut ShciBleInitCmdPacket = &mut packet;
|
||||
let packet_ptr: *mut _ = &mut packet;
|
||||
|
||||
unsafe {
|
||||
let cmd_ptr: *mut CmdPacket = packet_ptr.cast();
|
||||
|
||||
(*cmd_ptr).cmd_serial.cmd.cmd_code = SCHI_OPCODE_BLE_INIT;
|
||||
(*cmd_ptr).cmd_serial.cmd.payload_len = core::mem::size_of::<ShciBleInitCmdParam>() as u8;
|
||||
(*cmd_ptr).cmdserial.cmd.cmd_code = SCHI_OPCODE_BLE_INIT;
|
||||
(*cmd_ptr).cmdserial.cmd.payload_len = core::mem::size_of::<ShciBleInitCmdParam>() as u8;
|
||||
|
||||
let cmd_buf = &mut *(*TL_SYS_TABLE.as_mut_ptr()).pcmd_buffer;
|
||||
core::ptr::write(cmd_buf, *cmd_ptr);
|
||||
let p_cmd_buffer = &mut *(*TL_SYS_TABLE.as_mut_ptr()).pcmd_buffer;
|
||||
core::ptr::write(p_cmd_buffer, *cmd_ptr);
|
||||
|
||||
cmd_buf.cmd_serial.ty = TlPacketType::SysCmd as u8;
|
||||
p_cmd_buffer.cmdserial.ty = TlPacketType::SysCmd as u8;
|
||||
|
||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL);
|
||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
|
||||
sys::Sys::send_cmd();
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
use embassy_futures::block_on;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use super::cmd::{CmdPacket, CmdSerial};
|
||||
use super::consts::TlPacketType;
|
||||
use super::evt::{CcEvt, EvtBox, EvtSerial};
|
||||
use super::unsafe_linked_list::LinkedListNode;
|
||||
use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_CHANNEL, TL_REF_TABLE, TL_SYS_TABLE};
|
||||
use crate::tl_mbox::ipcc::Ipcc;
|
||||
use embassy_stm32::ipcc::Ipcc;
|
||||
|
||||
use crate::cmd::{CmdPacket, CmdSerial};
|
||||
use crate::evt::{CcEvt, EvtBox, EvtSerial};
|
||||
use crate::tables::SysTable;
|
||||
use crate::unsafe_linked_list::LinkedListNode;
|
||||
use crate::{channels, EVT_CHANNEL, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_SYS_TABLE};
|
||||
|
||||
pub struct Sys;
|
||||
|
||||
@ -14,34 +15,15 @@ impl Sys {
|
||||
unsafe {
|
||||
LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
|
||||
|
||||
TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable {
|
||||
TL_SYS_TABLE = MaybeUninit::new(SysTable {
|
||||
pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
|
||||
sys_queue: SYSTEM_EVT_QUEUE.as_ptr(),
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, true);
|
||||
}
|
||||
|
||||
pub fn evt_handler() {
|
||||
unsafe {
|
||||
let mut node_ptr = core::ptr::null_mut();
|
||||
let node_ptr_ptr: *mut _ = &mut node_ptr;
|
||||
|
||||
while !LinkedListNode::is_empty(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
|
||||
LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr(), node_ptr_ptr);
|
||||
|
||||
let event = node_ptr.cast();
|
||||
let event = EvtBox::new(event);
|
||||
|
||||
// TODO: not really happy about this
|
||||
block_on(TL_CHANNEL.send(event));
|
||||
}
|
||||
}
|
||||
|
||||
Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL);
|
||||
}
|
||||
|
||||
pub fn cmd_evt_handler() -> CcEvt {
|
||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false);
|
||||
|
||||
@ -55,29 +37,34 @@ impl Sys {
|
||||
// 4. CcEvt type is the actual SHCI response
|
||||
// 5. profit
|
||||
unsafe {
|
||||
let cmd: *const CmdPacket = (*TL_SYS_TABLE.as_ptr()).pcmd_buffer;
|
||||
let cmd_serial: *const CmdSerial = &(*cmd).cmd_serial;
|
||||
let pcmd: *const CmdPacket = (*TL_SYS_TABLE.as_ptr()).pcmd_buffer;
|
||||
let cmd_serial: *const CmdSerial = &(*pcmd).cmdserial;
|
||||
let evt_serial: *const EvtSerial = cmd_serial.cast();
|
||||
let cc = (*evt_serial).evt.payload.as_ptr().cast();
|
||||
let cc: *const CcEvt = (*evt_serial).evt.payload.as_ptr().cast();
|
||||
*cc
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn send_cmd(buf: &[u8]) {
|
||||
pub fn evt_handler() {
|
||||
unsafe {
|
||||
// TODO: check this
|
||||
let cmd_buffer = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer;
|
||||
let cmd_serial: *mut CmdSerial = &mut cmd_buffer.cmd_serial;
|
||||
let cmd_serial_buf = cmd_serial.cast();
|
||||
let mut node_ptr = core::ptr::null_mut();
|
||||
let node_ptr_ptr: *mut _ = &mut node_ptr;
|
||||
|
||||
core::ptr::copy(buf.as_ptr(), cmd_serial_buf, buf.len());
|
||||
while !LinkedListNode::is_empty(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
|
||||
LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr(), node_ptr_ptr);
|
||||
|
||||
let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer;
|
||||
cmd_packet.cmd_serial.ty = TlPacketType::SysCmd as u8;
|
||||
let event = node_ptr.cast();
|
||||
let event = EvtBox::new(event);
|
||||
|
||||
EVT_CHANNEL.try_send(event).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL);
|
||||
}
|
||||
|
||||
pub fn send_cmd() {
|
||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL);
|
||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
|
||||
}
|
||||
}
|
||||
}
|
175
embassy-stm32-wpan/src/tables.rs
Normal file
175
embassy-stm32-wpan/src/tables.rs
Normal file
@ -0,0 +1,175 @@
|
||||
use bit_field::BitField;
|
||||
|
||||
use crate::cmd::{AclDataPacket, CmdPacket};
|
||||
use crate::unsafe_linked_list::LinkedListNode;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct SafeBootInfoTable {
|
||||
version: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct RssInfoTable {
|
||||
pub version: u32,
|
||||
pub memory_size: u32,
|
||||
pub rss_info: u32,
|
||||
}
|
||||
|
||||
/**
|
||||
* Version
|
||||
* [0:3] = Build - 0: Untracked - 15:Released - x: Tracked version
|
||||
* [4:7] = branch - 0: Mass Market - x: ...
|
||||
* [8:15] = Subversion
|
||||
* [16:23] = Version minor
|
||||
* [24:31] = Version major
|
||||
*
|
||||
* Memory Size
|
||||
* [0:7] = Flash ( Number of 4k sector)
|
||||
* [8:15] = Reserved ( Shall be set to 0 - may be used as flash extension )
|
||||
* [16:23] = SRAM2b ( Number of 1k sector)
|
||||
* [24:31] = SRAM2a ( Number of 1k sector)
|
||||
*/
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct WirelessFwInfoTable {
|
||||
pub version: u32,
|
||||
pub memory_size: u32,
|
||||
pub thread_info: u32,
|
||||
pub ble_info: u32,
|
||||
}
|
||||
|
||||
impl WirelessFwInfoTable {
|
||||
pub fn version_major(&self) -> u8 {
|
||||
let version = self.version;
|
||||
(version.get_bits(24..31) & 0xff) as u8
|
||||
}
|
||||
|
||||
pub fn version_minor(&self) -> u8 {
|
||||
let version = self.version;
|
||||
(version.clone().get_bits(16..23) & 0xff) as u8
|
||||
}
|
||||
|
||||
pub fn subversion(&self) -> u8 {
|
||||
let version = self.version;
|
||||
(version.clone().get_bits(8..15) & 0xff) as u8
|
||||
}
|
||||
|
||||
/// Size of FLASH, expressed in number of 4K sectors.
|
||||
pub fn flash_size(&self) -> u8 {
|
||||
let memory_size = self.memory_size;
|
||||
(memory_size.clone().get_bits(0..7) & 0xff) as u8
|
||||
}
|
||||
|
||||
/// Size of SRAM2a, expressed in number of 1K sectors.
|
||||
pub fn sram2a_size(&self) -> u8 {
|
||||
let memory_size = self.memory_size;
|
||||
(memory_size.clone().get_bits(24..31) & 0xff) as u8
|
||||
}
|
||||
|
||||
/// Size of SRAM2b, expressed in number of 1K sectors.
|
||||
pub fn sram2b_size(&self) -> u8 {
|
||||
let memory_size = self.memory_size;
|
||||
(memory_size.clone().get_bits(16..23) & 0xff) as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C, align(4))]
|
||||
pub struct DeviceInfoTable {
|
||||
pub safe_boot_info_table: SafeBootInfoTable,
|
||||
pub rss_info_table: RssInfoTable,
|
||||
pub wireless_fw_info_table: WirelessFwInfoTable,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C, align(4))]
|
||||
pub struct BleTable {
|
||||
pub pcmd_buffer: *mut CmdPacket,
|
||||
pub pcs_buffer: *const u8,
|
||||
pub pevt_queue: *const u8,
|
||||
pub phci_acl_data_buffer: *mut AclDataPacket,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C, align(4))]
|
||||
pub struct ThreadTable {
|
||||
pub nostack_buffer: *const u8,
|
||||
pub clicmdrsp_buffer: *const u8,
|
||||
pub otcmdrsp_buffer: *const u8,
|
||||
}
|
||||
|
||||
// TODO: use later
|
||||
#[derive(Debug)]
|
||||
#[repr(C, align(4))]
|
||||
pub struct LldTestsTable {
|
||||
pub clicmdrsp_buffer: *const u8,
|
||||
pub m0cmd_buffer: *const u8,
|
||||
}
|
||||
|
||||
// TODO: use later
|
||||
#[derive(Debug)]
|
||||
#[repr(C, align(4))]
|
||||
pub struct BleLldTable {
|
||||
pub cmdrsp_buffer: *const u8,
|
||||
pub m0cmd_buffer: *const u8,
|
||||
}
|
||||
|
||||
// TODO: use later
|
||||
#[derive(Debug)]
|
||||
#[repr(C, align(4))]
|
||||
pub struct ZigbeeTable {
|
||||
pub notif_m0_to_m4_buffer: *const u8,
|
||||
pub appli_cmd_m4_to_m0_bufer: *const u8,
|
||||
pub request_m0_to_m4_buffer: *const u8,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C, align(4))]
|
||||
pub struct SysTable {
|
||||
pub pcmd_buffer: *mut CmdPacket,
|
||||
pub sys_queue: *const LinkedListNode,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C, align(4))]
|
||||
pub struct MemManagerTable {
|
||||
pub spare_ble_buffer: *const u8,
|
||||
pub spare_sys_buffer: *const u8,
|
||||
|
||||
pub blepool: *const u8,
|
||||
pub blepoolsize: u32,
|
||||
|
||||
pub pevt_free_buffer_queue: *mut LinkedListNode,
|
||||
|
||||
pub traces_evt_pool: *const u8,
|
||||
pub tracespoolsize: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C, align(4))]
|
||||
pub struct TracesTable {
|
||||
pub traces_queue: *const u8,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C, align(4))]
|
||||
pub struct Mac802_15_4Table {
|
||||
pub p_cmdrsp_buffer: *const u8,
|
||||
pub p_notack_buffer: *const u8,
|
||||
pub evt_queue: *const u8,
|
||||
}
|
||||
|
||||
/// Reference table. Contains pointers to all other tables.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct RefTable {
|
||||
pub device_info_table: *const DeviceInfoTable,
|
||||
pub ble_table: *const BleTable,
|
||||
pub thread_table: *const ThreadTable,
|
||||
pub sys_table: *const SysTable,
|
||||
pub mem_manager_table: *const MemManagerTable,
|
||||
pub traces_table: *const TracesTable,
|
||||
pub mac_802_15_4_table: *const Mac802_15_4Table,
|
||||
}
|
@ -57,6 +57,7 @@ impl LinkedListNode {
|
||||
});
|
||||
}
|
||||
|
||||
/// Remove `node` from the linked list
|
||||
pub unsafe fn remove_node(mut node: *mut LinkedListNode) {
|
||||
interrupt::free(|_| {
|
||||
(*(*node).prev).next = (*node).next;
|
||||
@ -64,6 +65,7 @@ impl LinkedListNode {
|
||||
});
|
||||
}
|
||||
|
||||
/// Remove `list_head` into `node`
|
||||
pub unsafe fn remove_head(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
|
||||
interrupt::free(|_| {
|
||||
*node = (*list_head).next;
|
||||
@ -71,10 +73,11 @@ impl LinkedListNode {
|
||||
});
|
||||
}
|
||||
|
||||
pub unsafe fn remove_tail(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
|
||||
/// Remove `list_tail` into `node`
|
||||
pub unsafe fn remove_tail(mut list_tail: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
|
||||
interrupt::free(|_| {
|
||||
*node = (*list_head).prev;
|
||||
Self::remove_node((*list_head).prev);
|
||||
*node = (*list_tail).prev;
|
||||
Self::remove_node((*list_tail).prev);
|
||||
});
|
||||
}
|
||||
|
@ -167,8 +167,68 @@ impl sealed::Instance for crate::peripherals::IPCC {
|
||||
}
|
||||
|
||||
unsafe fn _configure_pwr() {
|
||||
let pwr = crate::pac::PWR;
|
||||
let rcc = crate::pac::RCC;
|
||||
|
||||
rcc.cfgr().modify(|w| w.set_stopwuck(true));
|
||||
|
||||
pwr.cr1().modify(|w| w.set_dbp(true));
|
||||
pwr.cr1().modify(|w| w.set_dbp(true));
|
||||
|
||||
// configure LSE
|
||||
rcc.bdcr().modify(|w| w.set_lseon(true));
|
||||
|
||||
// select system clock source = PLL
|
||||
// set PLL coefficients
|
||||
// m: 2,
|
||||
// n: 12,
|
||||
// r: 3,
|
||||
// q: 4,
|
||||
// p: 3,
|
||||
let src_bits = 0b11;
|
||||
let pllp = (3 - 1) & 0b11111;
|
||||
let pllq = (4 - 1) & 0b111;
|
||||
let pllr = (3 - 1) & 0b111;
|
||||
let plln = 12 & 0b1111111;
|
||||
let pllm = (2 - 1) & 0b111;
|
||||
rcc.pllcfgr().modify(|w| {
|
||||
w.set_pllsrc(src_bits);
|
||||
w.set_pllm(pllm);
|
||||
w.set_plln(plln);
|
||||
w.set_pllr(pllr);
|
||||
w.set_pllp(pllp);
|
||||
w.set_pllpen(true);
|
||||
w.set_pllq(pllq);
|
||||
w.set_pllqen(true);
|
||||
});
|
||||
// enable PLL
|
||||
rcc.cr().modify(|w| w.set_pllon(true));
|
||||
rcc.cr().write(|w| w.set_hsion(false));
|
||||
// while !rcc.cr().read().pllrdy() {}
|
||||
|
||||
// configure SYSCLK mux to use PLL clocl
|
||||
rcc.cfgr().modify(|w| w.set_sw(0b11));
|
||||
|
||||
// configure CPU1 & CPU2 dividers
|
||||
rcc.cfgr().modify(|w| w.set_hpre(0)); // not divided
|
||||
rcc.extcfgr().modify(|w| {
|
||||
w.set_c2hpre(0b1000); // div2
|
||||
w.set_shdhpre(0); // not divided
|
||||
});
|
||||
|
||||
// apply APB1 / APB2 values
|
||||
rcc.cfgr().modify(|w| {
|
||||
w.set_ppre1(0b000); // not divided
|
||||
w.set_ppre2(0b000); // not divided
|
||||
});
|
||||
|
||||
// TODO: required
|
||||
// set RF wake-up clock = LSE
|
||||
rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
|
||||
|
||||
// set LPTIM1 & LPTIM2 clock source
|
||||
rcc.ccipr().modify(|w| {
|
||||
w.set_lptim1sel(0b00); // PCLK
|
||||
w.set_lptim2sel(0b00); // PCLK
|
||||
});
|
||||
}
|
@ -41,6 +41,8 @@ pub mod crc;
|
||||
pub mod flash;
|
||||
#[cfg(all(spi_v1, rcc_f4))]
|
||||
pub mod i2s;
|
||||
#[cfg(stm32wb)]
|
||||
pub mod ipcc;
|
||||
pub mod pwm;
|
||||
#[cfg(quadspi)]
|
||||
pub mod qspi;
|
||||
@ -52,8 +54,6 @@ pub mod rtc;
|
||||
pub mod sdmmc;
|
||||
#[cfg(spi)]
|
||||
pub mod spi;
|
||||
#[cfg(stm32wb)]
|
||||
pub mod tl_mbox;
|
||||
#[cfg(usart)]
|
||||
pub mod usart;
|
||||
#[cfg(usb)]
|
||||
|
@ -1,49 +0,0 @@
|
||||
use super::PacketHeader;
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Cmd {
|
||||
pub cmd_code: u16,
|
||||
pub payload_len: u8,
|
||||
pub payload: [u8; 255],
|
||||
}
|
||||
|
||||
impl Default for Cmd {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
cmd_code: 0,
|
||||
payload_len: 0,
|
||||
payload: [0u8; 255],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct CmdSerial {
|
||||
pub ty: u8,
|
||||
pub cmd: Cmd,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct CmdPacket {
|
||||
pub header: PacketHeader,
|
||||
pub cmd_serial: CmdSerial,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AclDataSerial {
|
||||
pub ty: u8,
|
||||
pub handle: u16,
|
||||
pub length: u16,
|
||||
pub acl_data: [u8; 1],
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AclDataPacket {
|
||||
pub header: PacketHeader,
|
||||
pub acl_data_serial: AclDataSerial,
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
use super::evt::EvtPacket;
|
||||
use super::unsafe_linked_list::LinkedListNode;
|
||||
use super::{
|
||||
channels, MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE,
|
||||
SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE, TL_REF_TABLE,
|
||||
};
|
||||
use crate::tl_mbox::ipcc::Ipcc;
|
||||
|
||||
pub struct MemoryManager;
|
||||
|
||||
impl MemoryManager {
|
||||
pub fn enable() {
|
||||
unsafe {
|
||||
LinkedListNode::init_head(FREE_BUFF_QUEUE.as_mut_ptr());
|
||||
LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
|
||||
|
||||
TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable {
|
||||
spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
|
||||
spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
|
||||
ble_pool: EVT_POOL.as_ptr().cast(),
|
||||
ble_pool_size: POOL_SIZE as u32,
|
||||
pevt_free_buffer_queue: FREE_BUFF_QUEUE.as_mut_ptr(),
|
||||
traces_evt_pool: core::ptr::null(),
|
||||
traces_pool_size: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn evt_handler() {
|
||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false);
|
||||
Self::send_free_buf();
|
||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
|
||||
}
|
||||
|
||||
pub fn evt_drop(evt: *mut EvtPacket) {
|
||||
unsafe {
|
||||
let list_node = evt.cast();
|
||||
|
||||
LinkedListNode::remove_tail(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), list_node);
|
||||
}
|
||||
|
||||
let channel_is_busy = Ipcc::c1_is_active_flag(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
|
||||
|
||||
// postpone event buffer freeing to IPCC interrupt handler
|
||||
if channel_is_busy {
|
||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, true);
|
||||
} else {
|
||||
Self::send_free_buf();
|
||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
|
||||
}
|
||||
}
|
||||
|
||||
fn send_free_buf() {
|
||||
unsafe {
|
||||
let mut node_ptr = core::ptr::null_mut();
|
||||
let node_ptr_ptr: *mut _ = &mut node_ptr;
|
||||
|
||||
while !LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
|
||||
LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), node_ptr_ptr);
|
||||
LinkedListNode::insert_tail(
|
||||
(*(*TL_REF_TABLE.as_ptr()).mem_manager_table).pevt_free_buffer_queue,
|
||||
node_ptr,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,417 +0,0 @@
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use atomic_polyfill::{compiler_fence, Ordering};
|
||||
use bit_field::BitField;
|
||||
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::channel::Channel;
|
||||
|
||||
use self::ble::Ble;
|
||||
use self::cmd::{AclDataPacket, CmdPacket};
|
||||
use self::evt::{CsEvt, EvtBox};
|
||||
use self::mm::MemoryManager;
|
||||
use self::shci::{shci_ble_init, ShciBleInitCmdParam};
|
||||
use self::sys::Sys;
|
||||
use self::unsafe_linked_list::LinkedListNode;
|
||||
use crate::interrupt;
|
||||
use crate::interrupt::InterruptExt;
|
||||
use crate::peripherals::IPCC;
|
||||
pub use crate::tl_mbox::ipcc::Config;
|
||||
use crate::tl_mbox::ipcc::Ipcc;
|
||||
|
||||
mod ble;
|
||||
mod channels;
|
||||
mod cmd;
|
||||
mod consts;
|
||||
mod evt;
|
||||
mod ipcc;
|
||||
mod mm;
|
||||
mod shci;
|
||||
mod sys;
|
||||
mod unsafe_linked_list;
|
||||
|
||||
pub type PacketHeader = LinkedListNode;
|
||||
|
||||
const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::<PacketHeader>();
|
||||
const TL_EVT_HEADER_SIZE: usize = 3;
|
||||
const TL_CS_EVT_SIZE: usize = core::mem::size_of::<CsEvt>();
|
||||
|
||||
const CFG_TL_BLE_EVT_QUEUE_LENGTH: usize = 5;
|
||||
const CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255;
|
||||
const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE;
|
||||
|
||||
const POOL_SIZE: usize = CFG_TL_BLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4);
|
||||
|
||||
const fn divc(x: usize, y: usize) -> usize {
|
||||
(x + y - 1) / y
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SafeBootInfoTable {
|
||||
version: u32,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct FusInfoTable {
|
||||
version: u32,
|
||||
memory_size: u32,
|
||||
fus_info: u32,
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct ReceiveInterruptHandler {}
|
||||
|
||||
impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for ReceiveInterruptHandler {
|
||||
unsafe fn on_interrupt() {
|
||||
// info!("ipcc rx interrupt");
|
||||
|
||||
if Ipcc::is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) {
|
||||
sys::Sys::evt_handler();
|
||||
} else if Ipcc::is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) {
|
||||
ble::Ble::evt_handler();
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TransmitInterruptHandler {}
|
||||
|
||||
impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
|
||||
unsafe fn on_interrupt() {
|
||||
// info!("ipcc tx interrupt");
|
||||
|
||||
if Ipcc::is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) {
|
||||
// TODO: handle this case
|
||||
let _ = sys::Sys::cmd_evt_handler();
|
||||
} else if Ipcc::is_tx_pending(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL) {
|
||||
mm::MemoryManager::evt_handler();
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # Version
|
||||
/// - 0 -> 3 = Build - 0: Untracked - 15:Released - x: Tracked version
|
||||
/// - 4 -> 7 = branch - 0: Mass Market - x: ...
|
||||
/// - 8 -> 15 = Subversion
|
||||
/// - 16 -> 23 = Version minor
|
||||
/// - 24 -> 31 = Version major
|
||||
/// # Memory Size
|
||||
/// - 0 -> 7 = Flash ( Number of 4k sector)
|
||||
/// - 8 -> 15 = Reserved ( Shall be set to 0 - may be used as flash extension )
|
||||
/// - 16 -> 23 = SRAM2b ( Number of 1k sector)
|
||||
/// - 24 -> 31 = SRAM2a ( Number of 1k sector)
|
||||
#[repr(C, packed)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct WirelessFwInfoTable {
|
||||
version: u32,
|
||||
memory_size: u32,
|
||||
info_stack: u32,
|
||||
reserved: u32,
|
||||
}
|
||||
|
||||
impl WirelessFwInfoTable {
|
||||
pub fn version_major(&self) -> u8 {
|
||||
let version = self.version;
|
||||
(version.get_bits(24..31) & 0xff) as u8
|
||||
}
|
||||
|
||||
pub fn version_minor(&self) -> u8 {
|
||||
let version = self.version;
|
||||
(version.get_bits(16..23) & 0xff) as u8
|
||||
}
|
||||
|
||||
pub fn subversion(&self) -> u8 {
|
||||
let version = self.version;
|
||||
(version.get_bits(8..15) & 0xff) as u8
|
||||
}
|
||||
|
||||
/// size of FLASH, expressed in number of 4K sectors
|
||||
pub fn flash_size(&self) -> u8 {
|
||||
let memory_size = self.memory_size;
|
||||
(memory_size.get_bits(0..7) & 0xff) as u8
|
||||
}
|
||||
|
||||
/// size for SRAM2a, expressed in number of 1K sectors
|
||||
pub fn sram2a_size(&self) -> u8 {
|
||||
let memory_size = self.memory_size;
|
||||
(memory_size.get_bits(24..31) & 0xff) as u8
|
||||
}
|
||||
|
||||
/// size of SRAM2b, expressed in number of 1K sectors
|
||||
pub fn sram2b_size(&self) -> u8 {
|
||||
let memory_size = self.memory_size;
|
||||
(memory_size.get_bits(16..23) & 0xff) as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct DeviceInfoTable {
|
||||
pub safe_boot_info_table: SafeBootInfoTable,
|
||||
pub fus_info_table: FusInfoTable,
|
||||
pub wireless_fw_info_table: WirelessFwInfoTable,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct BleTable {
|
||||
pcmd_buffer: *mut CmdPacket,
|
||||
pcs_buffer: *const u8,
|
||||
pevt_queue: *const u8,
|
||||
phci_acl_data_buffer: *mut AclDataPacket,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct ThreadTable {
|
||||
no_stack_buffer: *const u8,
|
||||
cli_cmd_rsp_buffer: *const u8,
|
||||
ot_cmd_rsp_buffer: *const u8,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct SysTable {
|
||||
pcmd_buffer: *mut CmdPacket,
|
||||
sys_queue: *const LinkedListNode,
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
#[repr(C, packed)]
|
||||
struct LldTestTable {
|
||||
cli_cmd_rsp_buffer: *const u8,
|
||||
m0_cmd_buffer: *const u8,
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
#[repr(C, packed)]
|
||||
struct BleLldTable {
|
||||
cmd_rsp_buffer: *const u8,
|
||||
m0_cmd_buffer: *const u8,
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
#[repr(C, packed)]
|
||||
struct ZigbeeTable {
|
||||
notif_m0_to_m4_buffer: *const u8,
|
||||
appli_cmd_m4_to_m0_buffer: *const u8,
|
||||
request_m0_to_m4_buffer: *const u8,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct MemManagerTable {
|
||||
spare_ble_buffer: *const u8,
|
||||
spare_sys_buffer: *const u8,
|
||||
|
||||
ble_pool: *const u8,
|
||||
ble_pool_size: u32,
|
||||
|
||||
pevt_free_buffer_queue: *mut LinkedListNode,
|
||||
|
||||
traces_evt_pool: *const u8,
|
||||
traces_pool_size: u32,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct TracesTable {
|
||||
traces_queue: *const u8,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct Mac802_15_4Table {
|
||||
pcmd_rsp_buffer: *const u8,
|
||||
pnotack_buffer: *const u8,
|
||||
evt_queue: *const u8,
|
||||
}
|
||||
|
||||
/// reference table. Contains pointers to all other tables
|
||||
#[repr(C, packed)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct RefTable {
|
||||
pub device_info_table: *const DeviceInfoTable,
|
||||
ble_table: *const BleTable,
|
||||
thread_table: *const ThreadTable,
|
||||
sys_table: *const SysTable,
|
||||
mem_manager_table: *const MemManagerTable,
|
||||
traces_table: *const TracesTable,
|
||||
mac_802_15_4_table: *const Mac802_15_4Table,
|
||||
zigbee_table: *const ZigbeeTable,
|
||||
lld_tests_table: *const LldTestTable,
|
||||
ble_lld_table: *const BleLldTable,
|
||||
}
|
||||
|
||||
#[link_section = "TL_REF_TABLE"]
|
||||
pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_LLD_TESTS_TABLE: MaybeUninit<LldTestTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_BLE_LLD_TABLE: MaybeUninit<BleLldTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut TL_ZIGBEE_TABLE: MaybeUninit<ZigbeeTable> = MaybeUninit::uninit();
|
||||
|
||||
#[allow(dead_code)] // Not used currently but reserved
|
||||
#[link_section = "MB_MEM1"]
|
||||
static mut FREE_BUFF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||
|
||||
// not in shared RAM
|
||||
static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> =
|
||||
MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
|
||||
MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
|
||||
MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
|
||||
|
||||
#[link_section = "MB_MEM2"]
|
||||
// "magic" numbers from ST ---v---v
|
||||
static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit();
|
||||
|
||||
// TODO: get a better size, this is a placeholder
|
||||
pub(crate) static TL_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 5> = Channel::new();
|
||||
|
||||
pub struct TlMbox<'d> {
|
||||
_ipcc: PeripheralRef<'d, IPCC>,
|
||||
}
|
||||
|
||||
impl<'d> TlMbox<'d> {
|
||||
/// initializes low-level transport between CPU1 and BLE stack on CPU2
|
||||
pub fn new(
|
||||
ipcc: impl Peripheral<P = IPCC> + 'd,
|
||||
_irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler>
|
||||
+ interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(ipcc);
|
||||
|
||||
unsafe {
|
||||
compiler_fence(Ordering::AcqRel);
|
||||
|
||||
TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable {
|
||||
device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
|
||||
ble_table: TL_BLE_TABLE.as_ptr(),
|
||||
thread_table: TL_THREAD_TABLE.as_ptr(),
|
||||
sys_table: TL_SYS_TABLE.as_ptr(),
|
||||
mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
|
||||
traces_table: TL_TRACES_TABLE.as_ptr(),
|
||||
mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(),
|
||||
zigbee_table: TL_ZIGBEE_TABLE.as_ptr(),
|
||||
lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(),
|
||||
ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(),
|
||||
});
|
||||
|
||||
// info!("TL_REF_TABLE addr: {:x}", TL_REF_TABLE.as_ptr() as usize);
|
||||
|
||||
compiler_fence(Ordering::AcqRel);
|
||||
|
||||
TL_SYS_TABLE = MaybeUninit::zeroed();
|
||||
TL_DEVICE_INFO_TABLE = MaybeUninit::zeroed();
|
||||
TL_BLE_TABLE = MaybeUninit::zeroed();
|
||||
TL_THREAD_TABLE = MaybeUninit::zeroed();
|
||||
TL_MEM_MANAGER_TABLE = MaybeUninit::zeroed();
|
||||
TL_TRACES_TABLE = MaybeUninit::zeroed();
|
||||
TL_MAC_802_15_4_TABLE = MaybeUninit::zeroed();
|
||||
TL_ZIGBEE_TABLE = MaybeUninit::zeroed();
|
||||
TL_LLD_TESTS_TABLE = MaybeUninit::zeroed();
|
||||
TL_BLE_LLD_TABLE = MaybeUninit::zeroed();
|
||||
|
||||
EVT_POOL = MaybeUninit::zeroed();
|
||||
SYS_SPARE_EVT_BUF = MaybeUninit::zeroed();
|
||||
BLE_SPARE_EVT_BUF = MaybeUninit::zeroed();
|
||||
|
||||
CS_BUFFER = MaybeUninit::zeroed();
|
||||
BLE_CMD_BUFFER = MaybeUninit::zeroed();
|
||||
HCI_ACL_DATA_BUFFER = MaybeUninit::zeroed();
|
||||
|
||||
compiler_fence(Ordering::AcqRel);
|
||||
}
|
||||
|
||||
Ipcc::enable(config);
|
||||
|
||||
Sys::enable();
|
||||
Ble::enable();
|
||||
MemoryManager::enable();
|
||||
|
||||
// enable interrupts
|
||||
crate::interrupt::IPCC_C1_RX.unpend();
|
||||
crate::interrupt::IPCC_C1_TX.unpend();
|
||||
|
||||
unsafe { crate::interrupt::IPCC_C1_RX.enable() };
|
||||
unsafe { crate::interrupt::IPCC_C1_TX.enable() };
|
||||
|
||||
Self { _ipcc: ipcc }
|
||||
}
|
||||
|
||||
pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> {
|
||||
let info = unsafe { &(*(*TL_REF_TABLE.as_ptr()).device_info_table).wireless_fw_info_table };
|
||||
|
||||
// zero version indicates that CPU2 wasn't active and didn't fill the information table
|
||||
if info.version != 0 {
|
||||
Some(*info)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shci_ble_init(&self, param: ShciBleInitCmdParam) {
|
||||
shci_ble_init(param);
|
||||
}
|
||||
|
||||
pub fn send_ble_cmd(&self, buf: &[u8]) {
|
||||
ble::Ble::send_cmd(buf);
|
||||
}
|
||||
|
||||
// pub fn send_sys_cmd(&self, buf: &[u8]) {
|
||||
// sys::Sys::send_cmd(buf);
|
||||
// }
|
||||
|
||||
pub async fn read(&self) -> EvtBox {
|
||||
TL_CHANNEL.recv().await
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["de
|
||||
embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] }
|
||||
embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
|
||||
|
||||
defmt = "0.3"
|
||||
defmt-rtt = "0.4"
|
||||
|
@ -4,14 +4,15 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::tl_mbox::{Config, TlMbox};
|
||||
use embassy_stm32::{bind_interrupts, tl_mbox};
|
||||
use embassy_stm32::bind_interrupts;
|
||||
use embassy_stm32::ipcc::Config;
|
||||
use embassy_stm32_wpan::TlMbox;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs{
|
||||
IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler;
|
||||
IPCC_C1_TX => tl_mbox::TransmitInterruptHandler;
|
||||
IPCC_C1_RX => embassy_stm32_wpan::ReceiveInterruptHandler;
|
||||
IPCC_C1_TX => embassy_stm32_wpan::TransmitInterruptHandler;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
@ -44,7 +45,7 @@ async fn main(_spawner: Spawner) {
|
||||
info!("Hello World!");
|
||||
|
||||
let config = Config::default();
|
||||
let mbox = TlMbox::new(p.IPCC, Irqs, config);
|
||||
let mbox = TlMbox::init(p.IPCC, Irqs, config);
|
||||
|
||||
loop {
|
||||
let wireless_fw_info = mbox.wireless_fw_info();
|
||||
|
@ -4,13 +4,15 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::tl_mbox::{Config, TlMbox};
|
||||
use embassy_stm32::{bind_interrupts, tl_mbox};
|
||||
use embassy_stm32::bind_interrupts;
|
||||
use embassy_stm32::ipcc::Config;
|
||||
use embassy_stm32_wpan::rc::RadioCoprocessor;
|
||||
use embassy_stm32_wpan::TlMbox;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs{
|
||||
IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler;
|
||||
IPCC_C1_TX => tl_mbox::TransmitInterruptHandler;
|
||||
IPCC_C1_RX => embassy_stm32_wpan::ReceiveInterruptHandler;
|
||||
IPCC_C1_TX => embassy_stm32_wpan::TransmitInterruptHandler;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
@ -43,55 +45,16 @@ async fn main(_spawner: Spawner) {
|
||||
info!("Hello World!");
|
||||
|
||||
let config = Config::default();
|
||||
let mbox = TlMbox::new(p.IPCC, Irqs, config);
|
||||
let mbox = TlMbox::init(p.IPCC, Irqs, config);
|
||||
|
||||
info!("waiting for coprocessor to boot");
|
||||
let event_box = mbox.read().await;
|
||||
let mut rc = RadioCoprocessor::new(mbox);
|
||||
|
||||
let mut payload = [0u8; 6];
|
||||
event_box.copy_into_slice(&mut payload).unwrap();
|
||||
let response = rc.read().await;
|
||||
info!("coprocessor ready {}", response);
|
||||
|
||||
let event_packet = event_box.evt();
|
||||
let kind = event_packet.evt_serial.kind;
|
||||
|
||||
// means recieved SYS event, which indicates in this case that the coprocessor is ready
|
||||
if kind == 0x12 {
|
||||
let code = event_packet.evt_serial.evt.evt_code;
|
||||
let payload_len = event_packet.evt_serial.evt.payload_len;
|
||||
|
||||
info!(
|
||||
"==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}",
|
||||
kind,
|
||||
code,
|
||||
payload_len,
|
||||
payload[3..]
|
||||
);
|
||||
}
|
||||
|
||||
// initialize ble stack, does not return a response
|
||||
mbox.shci_ble_init(Default::default());
|
||||
|
||||
info!("resetting BLE");
|
||||
mbox.send_ble_cmd(&[0x01, 0x03, 0x0c, 0x00, 0x00]);
|
||||
|
||||
let event_box = mbox.read().await;
|
||||
|
||||
let mut payload = [0u8; 7];
|
||||
event_box.copy_into_slice(&mut payload).unwrap();
|
||||
|
||||
let event_packet = event_box.evt();
|
||||
let kind = event_packet.evt_serial.kind;
|
||||
|
||||
let code = event_packet.evt_serial.evt.evt_code;
|
||||
let payload_len = event_packet.evt_serial.evt.payload_len;
|
||||
|
||||
info!(
|
||||
"==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}",
|
||||
kind,
|
||||
code,
|
||||
payload_len,
|
||||
payload[3..]
|
||||
);
|
||||
rc.write(&[0x01, 0x03, 0x0c, 0x00, 0x00]);
|
||||
let response = rc.read().await;
|
||||
info!("ble reset rsp {}", response);
|
||||
|
||||
info!("Test OK");
|
||||
cortex_m::asm::bkpt();
|
||||
|
@ -12,13 +12,13 @@ stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma"] # Nucleo
|
||||
stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo
|
||||
stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo
|
||||
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo
|
||||
stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble"] # Nucleo
|
||||
stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma" ] # Nucleo
|
||||
stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo
|
||||
stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board
|
||||
|
||||
sdmmc = []
|
||||
chrono = ["embassy-stm32/chrono", "dep:chrono"]
|
||||
ble = []
|
||||
ble = ["dep:embassy-stm32-wpan"]
|
||||
not-gpdma = []
|
||||
|
||||
[dependencies]
|
||||
@ -29,6 +29,7 @@ embassy-executor = { version = "0.2.0", path = "../../embassy-executor", feature
|
||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] }
|
||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] }
|
||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||
embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg"] }
|
||||
|
||||
defmt = "0.3.0"
|
||||
defmt-rtt = "0.4"
|
||||
|
@ -8,13 +8,14 @@ mod common;
|
||||
|
||||
use common::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::tl_mbox::{Config, TlMbox};
|
||||
use embassy_stm32::{bind_interrupts, tl_mbox};
|
||||
use embassy_stm32::bind_interrupts;
|
||||
use embassy_stm32::ipcc::Config;
|
||||
use embassy_stm32_wpan::TlMbox;
|
||||
use embassy_time::{Duration, Timer};
|
||||
|
||||
bind_interrupts!(struct Irqs{
|
||||
IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler;
|
||||
IPCC_C1_TX => tl_mbox::TransmitInterruptHandler;
|
||||
IPCC_C1_RX => embassy_stm32_wpan::ReceiveInterruptHandler;
|
||||
IPCC_C1_TX => embassy_stm32_wpan::TransmitInterruptHandler;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
@ -23,7 +24,7 @@ async fn main(_spawner: Spawner) {
|
||||
info!("Hello World!");
|
||||
|
||||
let config = Config::default();
|
||||
let mbox = TlMbox::new(p.IPCC, Irqs, config);
|
||||
let mbox = TlMbox::init(p.IPCC, Irqs, config);
|
||||
|
||||
loop {
|
||||
let wireless_fw_info = mbox.wireless_fw_info();
|
||||
@ -49,6 +50,15 @@ async fn main(_spawner: Spawner) {
|
||||
Timer::after(Duration::from_millis(50)).await;
|
||||
}
|
||||
|
||||
// let mut rc = RadioCoprocessor::new(mbox);
|
||||
//
|
||||
// let response = rc.read().await;
|
||||
// info!("coprocessor ready {}", response);
|
||||
//
|
||||
// rc.write(&[0x01, 0x03, 0x0c, 0x00, 0x00]);
|
||||
// let response = rc.read().await;
|
||||
// info!("ble reset rsp {}", response);
|
||||
|
||||
info!("Test OK");
|
||||
cortex_m::asm::bkpt();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user