Add docs for the BLE bindings
These new docs explain a lot of the current implementation for the BLE stack, with reference to AN5289 14.1. They also detail the additional requirements around BLE startup behaviour; specifically, that certain SYS events must be awaited, and that shci_c2_ble_init should be called. Since the ble feature is now enabled by default for the docs, the remaining documentation for the BLE behaviour (as implemented by the `stm32wb-hci` crate) should be bought in automatically.
This commit is contained in:
parent
c84aef75af
commit
b2cc2fda26
@ -37,6 +37,7 @@ pub use crate::sub::ble::hci;
|
||||
|
||||
type PacketHeader = LinkedListNode;
|
||||
|
||||
/// Transport Layer for the Mailbox interface
|
||||
pub struct TlMbox<'d> {
|
||||
_ipcc: PeripheralRef<'d, IPCC>,
|
||||
|
||||
@ -49,6 +50,33 @@ pub struct TlMbox<'d> {
|
||||
}
|
||||
|
||||
impl<'d> TlMbox<'d> {
|
||||
/// Initialise the Transport Layer, and creates and returns a wrapper around it.
|
||||
///
|
||||
/// This method performs the initialisation laid out in AN5289 annex 14.1. However, it differs
|
||||
/// from the implementation documented in Figure 64, to avoid needing to reference any C
|
||||
/// function pointers.
|
||||
///
|
||||
/// Annex 14.1 lays out the following methods that should be called:
|
||||
/// 1. tl_mbox.c/TL_Init, which initialises the reference table that is shared between CPU1
|
||||
/// and CPU2.
|
||||
/// 2. shci_tl.c/shci_init(), which initialises the system transport layer, and in turn
|
||||
/// calls tl_mbox.c/TL_SYS_Init, which initialises SYSTEM_EVT_QUEUE channel.
|
||||
/// 3. tl_mbox.c/TL_MM_Init(), which initialises the channel used for sending memory
|
||||
/// manager commands.
|
||||
/// 4. tl_mbox.c/TL_Enable(), which enables the IPCC, and starts CPU2.
|
||||
/// This implementation initialises all of the shared refernce tables and all IPCC channel that
|
||||
/// would be initialised by this process. The developer should therefore treat this method as
|
||||
/// completing all steps in Figure 64.
|
||||
///
|
||||
/// Once this method has been called, no system commands may be sent until the CPU2 ready
|
||||
/// signal is received, via [sys_subsystem.read]; this completes the procedure laid out in
|
||||
/// Figure 65.
|
||||
///
|
||||
/// If the `ble` feature is enabled, at this point, the user should call
|
||||
/// [sys_subsystem.shci_c2_ble_init], before any commands are written to the [ble_subsystem]
|
||||
/// ([Ble::new()] completes the process that would otherwise be handled by `TL_BLE_Init`; see
|
||||
/// Figure 66). This completes the procedure laid out in Figure 66.
|
||||
// TODO: document what the user should do after calling init to use the mac_802_15_4 subsystem
|
||||
pub fn init(
|
||||
ipcc: impl Peripheral<P = IPCC> + 'd,
|
||||
_irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler>
|
||||
@ -57,6 +85,9 @@ impl<'d> TlMbox<'d> {
|
||||
) -> Self {
|
||||
into_ref!(ipcc);
|
||||
|
||||
// this is an inlined version of TL_Init from the STM32WB firmware as requested by AN5289.
|
||||
// HW_IPCC_Init is not called, and its purpose is (presumably?) covered by this
|
||||
// implementation
|
||||
unsafe {
|
||||
TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable {
|
||||
device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
|
||||
@ -140,6 +171,7 @@ impl<'d> TlMbox<'d> {
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
// this is equivalent to `HW_IPCC_Enable`, which is called by `TL_Enable`
|
||||
Ipcc::enable(config);
|
||||
|
||||
Self {
|
||||
|
||||
@ -11,11 +11,20 @@ use crate::tables::{BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA
|
||||
use crate::unsafe_linked_list::LinkedListNode;
|
||||
use crate::{channels, evt};
|
||||
|
||||
/// A guard that, once constructed, may be used to send BLE commands to CPU2.
|
||||
///
|
||||
/// It is the responsibility of the caller to ensure that they have awaited an event via
|
||||
/// [crate::sub::Sys::read] before sending any of these commands, and to call
|
||||
/// [crate::sub::Sys::shci_c2_ble_init] and await the HCI_COMMAND_COMPLETE_EVENT before sending any
|
||||
/// other commands.
|
||||
pub struct Ble {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl Ble {
|
||||
/// Constructs a guard that allows for BLE commands to be sent to CPU2.
|
||||
///
|
||||
/// This takes the place of `TL_BLE_Init`, completing that step as laid out in AN5289, Fig 66.
|
||||
pub(crate) fn new() -> Self {
|
||||
unsafe {
|
||||
LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
|
||||
@ -30,6 +39,7 @@ impl Ble {
|
||||
|
||||
Self { _private: () }
|
||||
}
|
||||
|
||||
/// `HW_IPCC_BLE_EvtNot`
|
||||
pub async fn tl_read(&self) -> EvtBox<Self> {
|
||||
Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe {
|
||||
|
||||
@ -10,6 +10,7 @@ use crate::tables::{SysTable, WirelessFwInfoTable};
|
||||
use crate::unsafe_linked_list::LinkedListNode;
|
||||
use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE};
|
||||
|
||||
/// A guard that, once constructed, allows for sys commands to be sent to CPU2.
|
||||
pub struct Sys {
|
||||
_private: (),
|
||||
}
|
||||
@ -86,12 +87,21 @@ impl Sys {
|
||||
self.write_and_get_response(ShciOpcode::Mac802_15_4Init, &[]).await
|
||||
}
|
||||
|
||||
/// Send a request to CPU2 to initialise the BLE stack.
|
||||
///
|
||||
/// This must be called before any BLE commands are sent via the BLE channel (according to
|
||||
/// AN5289, Figures 65 and 66). It should only be called after CPU2 sends a system event, via
|
||||
/// `HW_IPCC_SYS_EvtNot`, aka `IoBusCallBackUserEvt` (as detailed in Figure 65), aka [read].
|
||||
#[cfg(feature = "ble")]
|
||||
pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> Result<SchiCommandStatus, ()> {
|
||||
self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await
|
||||
}
|
||||
|
||||
/// `HW_IPCC_SYS_EvtNot`
|
||||
///
|
||||
/// This method takes the place of the `HW_IPCC_SYS_EvtNot`/`SysUserEvtRx`/`APPE_SysUserEvtRx`,
|
||||
/// as the embassy implementation avoids the need to call C public bindings, and instead
|
||||
/// handles the event channels directly.
|
||||
pub async fn read(&self) -> EvtBox<mm::MemoryManager> {
|
||||
Ipcc::receive(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, || unsafe {
|
||||
if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
|
||||
|
||||
@ -89,12 +89,19 @@ pub struct DeviceInfoTable {
|
||||
pub wireless_fw_info_table: WirelessFwInfoTable,
|
||||
}
|
||||
|
||||
/// The bluetooth reference table, as defined in figure 67 of STM32WX AN5289.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct BleTable {
|
||||
/// A pointer to the buffer that is used for sending BLE commands.
|
||||
pub pcmd_buffer: *mut CmdPacket,
|
||||
/// A pointer to the buffer used for storing Command statuses.
|
||||
pub pcs_buffer: *const u8,
|
||||
/// A pointer to the event queue, over which IPCC BLE events are sent. This may be accessed via
|
||||
/// [crate::sub::ble::tl_read].
|
||||
pub pevt_queue: *const u8,
|
||||
/// A pointer to the buffer that is used for sending HCI (Host-Controller Interface) ACL
|
||||
/// (Asynchronous Connection-oriented Logical transport) commands (unused).
|
||||
pub phci_acl_data_buffer: *mut AclDataPacket,
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user