tl_mbox read and write
This commit is contained in:
		@@ -158,6 +158,10 @@ impl<'d> Ipcc<'d> {
 | 
			
		||||
    pub fn is_rx_pending(&self, channel: IpccChannel) -> bool {
 | 
			
		||||
        self.c2_is_active_flag(channel) && self.c1_get_rx_channel(channel)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn as_mut_ptr(&self) -> *mut Self {
 | 
			
		||||
        unsafe { &mut core::ptr::read(self) as *mut _ }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl sealed::Instance for crate::peripherals::IPCC {
 | 
			
		||||
@@ -176,3 +180,14 @@ unsafe fn _configure_pwr() {
 | 
			
		||||
    // set RF wake-up clock = LSE
 | 
			
		||||
    rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: if anyone has a better idea, please let me know
 | 
			
		||||
/// extension trait that constrains the [`Ipcc`] peripheral
 | 
			
		||||
pub trait IpccExt<'d> {
 | 
			
		||||
    fn constrain(self) -> Ipcc<'d>;
 | 
			
		||||
}
 | 
			
		||||
impl<'d> IpccExt<'d> for IPCC {
 | 
			
		||||
    fn constrain(self) -> Ipcc<'d> {
 | 
			
		||||
        Ipcc { _peri: self.into_ref() }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,22 @@
 | 
			
		||||
use core::mem::MaybeUninit;
 | 
			
		||||
 | 
			
		||||
use super::unsafe_linked_list::LST_init_head;
 | 
			
		||||
use super::{channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE};
 | 
			
		||||
use embassy_futures::block_on;
 | 
			
		||||
 | 
			
		||||
use super::cmd::CmdSerial;
 | 
			
		||||
use super::consts::TlPacketType;
 | 
			
		||||
use super::evt::EvtBox;
 | 
			
		||||
use super::unsafe_linked_list::{LST_init_head, LST_is_empty, LST_remove_head};
 | 
			
		||||
use super::{
 | 
			
		||||
    channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE, TL_CHANNEL,
 | 
			
		||||
    TL_REF_TABLE,
 | 
			
		||||
};
 | 
			
		||||
use crate::ipcc::Ipcc;
 | 
			
		||||
use crate::tl_mbox::cmd::CmdPacket;
 | 
			
		||||
 | 
			
		||||
pub struct Ble;
 | 
			
		||||
 | 
			
		||||
impl Ble {
 | 
			
		||||
    pub fn new(ipcc: &mut Ipcc) -> Self {
 | 
			
		||||
    pub(crate) fn new(ipcc: &mut Ipcc) -> Self {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            LST_init_head(EVT_QUEUE.as_mut_ptr());
 | 
			
		||||
 | 
			
		||||
@@ -23,4 +32,37 @@ impl Ble {
 | 
			
		||||
 | 
			
		||||
        Ble
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn evt_handler(ipcc: &mut Ipcc) {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            let mut node_ptr = core::ptr::null_mut();
 | 
			
		||||
            let node_ptr_ptr: *mut _ = &mut node_ptr;
 | 
			
		||||
 | 
			
		||||
            while !LST_is_empty(EVT_QUEUE.as_mut_ptr()) {
 | 
			
		||||
                LST_remove_head(EVT_QUEUE.as_mut_ptr(), node_ptr_ptr);
 | 
			
		||||
 | 
			
		||||
                let event = node_ptr.cast();
 | 
			
		||||
                let event = EvtBox::new(event);
 | 
			
		||||
 | 
			
		||||
                block_on(TL_CHANNEL.send(event));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ipcc.c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn send_cmd(ipcc: &mut Ipcc, buf: &[u8]) {
 | 
			
		||||
        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_buf: *mut u8 = pcmd_serial.cast();
 | 
			
		||||
 | 
			
		||||
            core::ptr::copy(buf.as_ptr(), pcmd_serial_buf, buf.len());
 | 
			
		||||
 | 
			
		||||
            let mut cmd_packet = &mut *(*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
 | 
			
		||||
            cmd_packet.cmd_serial.ty = TlPacketType::BleCmd as u8;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ipcc.c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -52,9 +52,9 @@
 | 
			
		||||
pub mod cpu1 {
 | 
			
		||||
    use crate::ipcc::IpccChannel;
 | 
			
		||||
 | 
			
		||||
    #[allow(dead_code)] // Not used currently but reserved
 | 
			
		||||
    // Not used currently but reserved
 | 
			
		||||
    pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1;
 | 
			
		||||
    #[allow(dead_code)] // Not used currently but reserved
 | 
			
		||||
    // 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;
 | 
			
		||||
@@ -62,7 +62,7 @@ pub mod cpu1 {
 | 
			
		||||
    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;
 | 
			
		||||
    #[allow(dead_code)] // Not used currently but reserved
 | 
			
		||||
    // 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_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
 | 
			
		||||
@@ -88,7 +88,7 @@ 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;
 | 
			
		||||
    pub const IPCC_BLE_LLD_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
 | 
			
		||||
    #[allow(dead_code)] // Not used currently but reserved
 | 
			
		||||
    pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4;
 | 
			
		||||
    #[allow(dead_code)] // Not used currently but reserved
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								embassy-stm32/src/tl_mbox/consts.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								embassy-stm32/src/tl_mbox/consts.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
#[derive(PartialEq)]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
pub enum TlPacketType {
 | 
			
		||||
    BleCmd = 0x01,
 | 
			
		||||
    AclData = 0x02,
 | 
			
		||||
    BleEvt = 0x04,
 | 
			
		||||
 | 
			
		||||
    OtCmd = 0x08,
 | 
			
		||||
    OtRsp = 0x09,
 | 
			
		||||
    CliCmd = 0x0A,
 | 
			
		||||
    OtNot = 0x0C,
 | 
			
		||||
    OtAck = 0x0D,
 | 
			
		||||
    CliNot = 0x0E,
 | 
			
		||||
    CliAck = 0x0F,
 | 
			
		||||
 | 
			
		||||
    SysCmd = 0x10,
 | 
			
		||||
    SysRsp = 0x11,
 | 
			
		||||
    SysEvt = 0x12,
 | 
			
		||||
 | 
			
		||||
    LocCmd = 0x20,
 | 
			
		||||
    LocRsp = 0x21,
 | 
			
		||||
 | 
			
		||||
    TracesApp = 0x40,
 | 
			
		||||
    TracesWl = 0x41,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TryFrom<u8> for TlPacketType {
 | 
			
		||||
    type Error = ();
 | 
			
		||||
 | 
			
		||||
    fn try_from(value: u8) -> Result<Self, Self::Error> {
 | 
			
		||||
        match value {
 | 
			
		||||
            0x01 => Ok(TlPacketType::BleCmd),
 | 
			
		||||
            0x02 => Ok(TlPacketType::AclData),
 | 
			
		||||
            0x04 => Ok(TlPacketType::BleEvt),
 | 
			
		||||
            0x08 => Ok(TlPacketType::OtCmd),
 | 
			
		||||
            0x09 => Ok(TlPacketType::OtRsp),
 | 
			
		||||
            0x0A => Ok(TlPacketType::CliCmd),
 | 
			
		||||
            0x0C => Ok(TlPacketType::OtNot),
 | 
			
		||||
            0x0D => Ok(TlPacketType::OtAck),
 | 
			
		||||
            0x0E => Ok(TlPacketType::CliNot),
 | 
			
		||||
            0x0F => Ok(TlPacketType::CliAck),
 | 
			
		||||
            0x10 => Ok(TlPacketType::SysCmd),
 | 
			
		||||
            0x11 => Ok(TlPacketType::SysRsp),
 | 
			
		||||
            0x12 => Ok(TlPacketType::SysEvt),
 | 
			
		||||
            0x20 => Ok(TlPacketType::LocCmd),
 | 
			
		||||
            0x21 => Ok(TlPacketType::LocRsp),
 | 
			
		||||
            0x40 => Ok(TlPacketType::TracesApp),
 | 
			
		||||
            0x41 => Ok(TlPacketType::TracesWl),
 | 
			
		||||
 | 
			
		||||
            _ => Err(()),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +1,10 @@
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
/// the payload of [`Evt`] for a command status event
 | 
			
		||||
#[derive(Copy, Clone)]
 | 
			
		||||
#[repr(C, packed)]
 | 
			
		||||
@@ -6,3 +13,159 @@ pub struct CsEvt {
 | 
			
		||||
    pub num_cmd: u8,
 | 
			
		||||
    pub cmd_code: u16,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// the payload of [`Evt`] for a command complete event
 | 
			
		||||
#[derive(Clone, Copy, Default)]
 | 
			
		||||
#[repr(C, packed)]
 | 
			
		||||
pub struct CcEvt {
 | 
			
		||||
    pub num_cmd: u8,
 | 
			
		||||
    pub cmd_code: u8,
 | 
			
		||||
    pub payload: [u8; 1],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy, Default)]
 | 
			
		||||
#[repr(C, packed)]
 | 
			
		||||
pub struct Evt {
 | 
			
		||||
    pub evt_code: u8,
 | 
			
		||||
    pub payload_len: u8,
 | 
			
		||||
    pub payload: [u8; 1],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy, Default)]
 | 
			
		||||
#[repr(C, packed)]
 | 
			
		||||
pub struct EvtSerial {
 | 
			
		||||
    pub kind: u8,
 | 
			
		||||
    pub evt: Evt,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// This format shall be used for all events (asynchronous and command response) reported
 | 
			
		||||
/// by the CPU2 except for the command response of a system command where the header is not there
 | 
			
		||||
/// and the format to be used shall be `EvtSerial`.
 | 
			
		||||
///
 | 
			
		||||
/// ### Note:
 | 
			
		||||
/// 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)]
 | 
			
		||||
#[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
 | 
			
		||||
pub struct EvtBox {
 | 
			
		||||
    ptr: *mut EvtPacket,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsafe impl Send for EvtBox {}
 | 
			
		||||
impl EvtBox {
 | 
			
		||||
    pub(super) fn new(ptr: *mut EvtPacket) -> Self {
 | 
			
		||||
        Self { ptr }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Copies the event data from inner pointer and returns and event structure
 | 
			
		||||
    pub fn evt(&self) -> EvtPacket {
 | 
			
		||||
        let mut evt = MaybeUninit::uninit();
 | 
			
		||||
        unsafe {
 | 
			
		||||
            self.ptr.copy_to(evt.as_mut_ptr(), 1);
 | 
			
		||||
            evt.assume_init()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// 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, ()> {
 | 
			
		||||
        // TODO: double check this
 | 
			
		||||
        // unsafe {
 | 
			
		||||
        //     let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
 | 
			
		||||
 | 
			
		||||
        //     if let TlPacketType::AclData = evt_kind {
 | 
			
		||||
        //         let acl_data: *const AclDataPacket = self.ptr.cast();
 | 
			
		||||
        //         let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
 | 
			
		||||
        //         let acl_serial_buf: *const u8 = acl_serial.cast();
 | 
			
		||||
 | 
			
		||||
        //         let len = (*acl_serial).length as usize + 5;
 | 
			
		||||
        //         if len > buf.len() {
 | 
			
		||||
        //             return Err(());
 | 
			
		||||
        //         }
 | 
			
		||||
 | 
			
		||||
        //         core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len);
 | 
			
		||||
 | 
			
		||||
        //         Ok(len)
 | 
			
		||||
        //     } else {
 | 
			
		||||
        //         let evt_data: *const EvtPacket = self.ptr.cast();
 | 
			
		||||
        //         let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
 | 
			
		||||
        //         let evt_serial_buf: *const u8 = evt_serial.cast();
 | 
			
		||||
 | 
			
		||||
        //         let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
 | 
			
		||||
        //         if len > buf.len() {
 | 
			
		||||
        //             return Err(());
 | 
			
		||||
        //         }
 | 
			
		||||
 | 
			
		||||
        //         core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len);
 | 
			
		||||
 | 
			
		||||
        //         Ok(len)
 | 
			
		||||
        //     }
 | 
			
		||||
        // }
 | 
			
		||||
 | 
			
		||||
        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 evt_serial_buf: *const u8 = evt_serial.cast();
 | 
			
		||||
 | 
			
		||||
            let acl_data: *const AclDataPacket = self.ptr.cast();
 | 
			
		||||
            let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
 | 
			
		||||
            let acl_serial_buf: *const u8 = acl_serial.cast();
 | 
			
		||||
 | 
			
		||||
            if let TlPacketType::AclData = evt_kind {
 | 
			
		||||
                let len = (*acl_serial).length as usize + 5;
 | 
			
		||||
                if len > buf.len() {
 | 
			
		||||
                    return Err(());
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len);
 | 
			
		||||
 | 
			
		||||
                Ok(len)
 | 
			
		||||
            } else {
 | 
			
		||||
                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)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Drop for EvtBox {
 | 
			
		||||
    fn drop(&mut self) {
 | 
			
		||||
        use crate::ipcc::IpccExt;
 | 
			
		||||
        let mut ipcc = unsafe { crate::Peripherals::steal() }.IPCC.constrain();
 | 
			
		||||
        mm::MemoryManager::evt_drop(self.ptr, &mut ipcc);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,12 @@
 | 
			
		||||
use core::mem::MaybeUninit;
 | 
			
		||||
 | 
			
		||||
use super::unsafe_linked_list::LST_init_head;
 | 
			
		||||
use super::evt::EvtPacket;
 | 
			
		||||
use super::unsafe_linked_list::{LST_init_head, LST_insert_tail, LST_is_empty, LST_remove_head};
 | 
			
		||||
use super::{
 | 
			
		||||
    MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, SYS_SPARE_EVT_BUF,
 | 
			
		||||
    TL_MEM_MANAGER_TABLE,
 | 
			
		||||
    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::ipcc::Ipcc;
 | 
			
		||||
 | 
			
		||||
pub struct MemoryManager;
 | 
			
		||||
 | 
			
		||||
@@ -27,4 +29,43 @@ impl MemoryManager {
 | 
			
		||||
 | 
			
		||||
        MemoryManager
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn evt_handler(ipcc: &mut Ipcc) {
 | 
			
		||||
        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, ipcc: &mut Ipcc) {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            let list_node = evt.cast();
 | 
			
		||||
 | 
			
		||||
            LST_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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn send_free_buf() {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            let mut node_ptr = core::ptr::null_mut();
 | 
			
		||||
            let node_ptr_ptr: *mut _ = &mut node_ptr;
 | 
			
		||||
 | 
			
		||||
            while !LST_is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
 | 
			
		||||
                LST_remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), node_ptr_ptr);
 | 
			
		||||
                LST_insert_tail(
 | 
			
		||||
                    (*(*TL_REF_TABLE.as_ptr()).mem_manager_table).pevt_free_buffer_queue,
 | 
			
		||||
                    node_ptr,
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +1,27 @@
 | 
			
		||||
use core::mem::MaybeUninit;
 | 
			
		||||
 | 
			
		||||
use bit_field::BitField;
 | 
			
		||||
use embassy_cortex_m::interrupt::InterruptExt;
 | 
			
		||||
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;
 | 
			
		||||
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::_generated::interrupt::{IPCC_C1_RX, IPCC_C1_TX};
 | 
			
		||||
use crate::ipcc::Ipcc;
 | 
			
		||||
 | 
			
		||||
mod ble;
 | 
			
		||||
mod channels;
 | 
			
		||||
mod cmd;
 | 
			
		||||
mod consts;
 | 
			
		||||
mod evt;
 | 
			
		||||
mod mm;
 | 
			
		||||
mod shci;
 | 
			
		||||
mod sys;
 | 
			
		||||
mod unsafe_linked_list;
 | 
			
		||||
 | 
			
		||||
@@ -236,18 +243,14 @@ static mut FREE_BUFF_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_MEM1"]
 | 
			
		||||
static mut TRACES_EVT_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_MEM1"]
 | 
			
		||||
#[link_section = "MB_MEM2"]
 | 
			
		||||
static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
 | 
			
		||||
 | 
			
		||||
#[link_section = "MB_MEM1"]
 | 
			
		||||
#[link_section = "MB_MEM2"]
 | 
			
		||||
static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
 | 
			
		||||
 | 
			
		||||
#[link_section = "MB_MEM2"]
 | 
			
		||||
@@ -271,6 +274,9 @@ static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
 | 
			
		||||
//                                            "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 {
 | 
			
		||||
    _sys: Sys,
 | 
			
		||||
    _ble: Ble,
 | 
			
		||||
@@ -279,7 +285,7 @@ pub struct TlMbox {
 | 
			
		||||
 | 
			
		||||
impl TlMbox {
 | 
			
		||||
    /// initializes low-level transport between CPU1 and BLE stack on CPU2
 | 
			
		||||
    pub fn init(ipcc: &mut Ipcc) -> TlMbox {
 | 
			
		||||
    pub fn init(ipcc: &mut Ipcc, rx_irq: IPCC_C1_RX, tx_irq: IPCC_C1_TX) -> TlMbox {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            TL_REF_TABLE = MaybeUninit::new(RefTable {
 | 
			
		||||
                device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
 | 
			
		||||
@@ -320,6 +326,24 @@ impl TlMbox {
 | 
			
		||||
        let _ble = Ble::new(ipcc);
 | 
			
		||||
        let _mm = MemoryManager::new();
 | 
			
		||||
 | 
			
		||||
        rx_irq.disable();
 | 
			
		||||
        tx_irq.disable();
 | 
			
		||||
 | 
			
		||||
        rx_irq.set_handler_context(ipcc.as_mut_ptr() as *mut ());
 | 
			
		||||
        tx_irq.set_handler_context(ipcc.as_mut_ptr() as *mut ());
 | 
			
		||||
 | 
			
		||||
        rx_irq.set_handler(|ipcc| {
 | 
			
		||||
            let ipcc: &mut Ipcc = unsafe { &mut *ipcc.cast() };
 | 
			
		||||
            Self::interrupt_ipcc_rx_handler(ipcc);
 | 
			
		||||
        });
 | 
			
		||||
        tx_irq.set_handler(|ipcc| {
 | 
			
		||||
            let ipcc: &mut Ipcc = unsafe { &mut *ipcc.cast() };
 | 
			
		||||
            Self::interrupt_ipcc_tx_handler(ipcc);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        rx_irq.enable();
 | 
			
		||||
        tx_irq.enable();
 | 
			
		||||
 | 
			
		||||
        TlMbox { _sys, _ble, _mm }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -333,4 +357,41 @@ impl TlMbox {
 | 
			
		||||
            None
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn shci_ble_init(&self, ipcc: &mut Ipcc, param: ShciBleInitCmdParam) {
 | 
			
		||||
        shci_ble_init(ipcc, param);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn send_ble_cmd(&self, ipcc: &mut Ipcc, buf: &[u8]) {
 | 
			
		||||
        ble::Ble::send_cmd(ipcc, buf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // pub fn send_sys_cmd(&self, ipcc: &mut Ipcc, buf: &[u8]) {
 | 
			
		||||
    //     sys::Sys::send_cmd(ipcc, buf);
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    pub async fn read(&self) -> EvtBox {
 | 
			
		||||
        TL_CHANNEL.recv().await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn interrupt_ipcc_rx_handler(ipcc: &mut Ipcc) {
 | 
			
		||||
        if ipcc.is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) {
 | 
			
		||||
            sys::Sys::evt_handler(ipcc);
 | 
			
		||||
        } else if ipcc.is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) {
 | 
			
		||||
            ble::Ble::evt_handler(ipcc);
 | 
			
		||||
        } else {
 | 
			
		||||
            todo!()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn interrupt_ipcc_tx_handler(ipcc: &mut Ipcc) {
 | 
			
		||||
        if ipcc.is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) {
 | 
			
		||||
            // TODO: handle this case
 | 
			
		||||
            let _ = sys::Sys::cmd_evt_handler(ipcc);
 | 
			
		||||
        } else if ipcc.is_tx_pending(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL) {
 | 
			
		||||
            mm::MemoryManager::evt_handler(ipcc);
 | 
			
		||||
        } else {
 | 
			
		||||
            todo!()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										101
									
								
								embassy-stm32/src/tl_mbox/shci.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								embassy-stm32/src/tl_mbox/shci.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
//! 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::ipcc::Ipcc;
 | 
			
		||||
 | 
			
		||||
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)]
 | 
			
		||||
#[repr(C, packed)]
 | 
			
		||||
pub struct ShciBleInitCmdParam {
 | 
			
		||||
    /// NOT USED CURRENTLY
 | 
			
		||||
    pub p_ble_buffer_address: u32,
 | 
			
		||||
 | 
			
		||||
    /// Size of the Buffer allocated in pBleBufferAddress
 | 
			
		||||
    pub ble_buffer_size: u32,
 | 
			
		||||
 | 
			
		||||
    pub num_attr_record: u16,
 | 
			
		||||
    pub num_attr_serv: u16,
 | 
			
		||||
    pub attr_value_arr_size: u16,
 | 
			
		||||
    pub num_of_links: u8,
 | 
			
		||||
    pub extended_packet_length_enable: u8,
 | 
			
		||||
    pub pr_write_list_size: u8,
 | 
			
		||||
    pub mb_lock_count: u8,
 | 
			
		||||
 | 
			
		||||
    pub att_mtu: u16,
 | 
			
		||||
    pub slave_sca: u16,
 | 
			
		||||
    pub master_sca: u8,
 | 
			
		||||
    pub ls_source: u8,
 | 
			
		||||
    pub max_conn_event_length: u32,
 | 
			
		||||
    pub hs_startup_time: u16,
 | 
			
		||||
    pub viterbi_enable: u8,
 | 
			
		||||
    pub ll_only: u8,
 | 
			
		||||
    pub hw_version: u8,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for ShciBleInitCmdParam {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            p_ble_buffer_address: 0,
 | 
			
		||||
            ble_buffer_size: 0,
 | 
			
		||||
            num_attr_record: 68,
 | 
			
		||||
            num_attr_serv: 8,
 | 
			
		||||
            attr_value_arr_size: 1344,
 | 
			
		||||
            num_of_links: 2,
 | 
			
		||||
            extended_packet_length_enable: 1,
 | 
			
		||||
            pr_write_list_size: 0x3A,
 | 
			
		||||
            mb_lock_count: 0x79,
 | 
			
		||||
            att_mtu: 156,
 | 
			
		||||
            slave_sca: 500,
 | 
			
		||||
            master_sca: 0,
 | 
			
		||||
            ls_source: 1,
 | 
			
		||||
            max_conn_event_length: 0xFFFFFFFF,
 | 
			
		||||
            hs_startup_time: 0x148,
 | 
			
		||||
            viterbi_enable: 1,
 | 
			
		||||
            ll_only: 0,
 | 
			
		||||
            hw_version: 0,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy, Default)]
 | 
			
		||||
#[repr(C, packed)]
 | 
			
		||||
pub struct ShciHeader {
 | 
			
		||||
    metadata: [u32; 3],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy)]
 | 
			
		||||
#[repr(C, packed)]
 | 
			
		||||
pub struct ShciBleInitCmdPacket {
 | 
			
		||||
    header: ShciHeader,
 | 
			
		||||
    param: ShciBleInitCmdParam,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn shci_ble_init(ipcc: &mut Ipcc, param: ShciBleInitCmdParam) {
 | 
			
		||||
    let mut packet = ShciBleInitCmdPacket {
 | 
			
		||||
        header: ShciHeader::default(),
 | 
			
		||||
        param,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let packet_ptr: *mut ShciBleInitCmdPacket = &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;
 | 
			
		||||
 | 
			
		||||
        let mut cmd_buf = &mut *(*TL_SYS_TABLE.as_mut_ptr()).pcmd_buffer;
 | 
			
		||||
        core::ptr::write(cmd_buf, *cmd_ptr);
 | 
			
		||||
 | 
			
		||||
        cmd_buf.cmd_serial.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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +1,18 @@
 | 
			
		||||
use core::mem::MaybeUninit;
 | 
			
		||||
 | 
			
		||||
use super::unsafe_linked_list::LST_init_head;
 | 
			
		||||
use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_SYS_TABLE};
 | 
			
		||||
use embassy_futures::block_on;
 | 
			
		||||
 | 
			
		||||
use super::cmd::{CmdPacket, CmdSerial};
 | 
			
		||||
use super::consts::TlPacketType;
 | 
			
		||||
use super::evt::{CcEvt, EvtBox, EvtSerial};
 | 
			
		||||
use super::unsafe_linked_list::{LST_init_head, LST_is_empty, LST_remove_head};
 | 
			
		||||
use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_CHANNEL, TL_REF_TABLE, TL_SYS_TABLE};
 | 
			
		||||
use crate::ipcc::Ipcc;
 | 
			
		||||
 | 
			
		||||
pub struct Sys;
 | 
			
		||||
 | 
			
		||||
impl Sys {
 | 
			
		||||
    pub fn new(ipcc: &mut Ipcc) -> Self {
 | 
			
		||||
    pub(crate) fn new(ipcc: &mut Ipcc) -> Self {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            LST_init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
 | 
			
		||||
 | 
			
		||||
@@ -21,4 +26,62 @@ impl Sys {
 | 
			
		||||
 | 
			
		||||
        Sys
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn evt_handler(ipcc: &mut Ipcc) {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            let mut node_ptr = core::ptr::null_mut();
 | 
			
		||||
            let node_ptr_ptr: *mut _ = &mut node_ptr;
 | 
			
		||||
 | 
			
		||||
            while !LST_is_empty(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
 | 
			
		||||
                LST_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(crate) fn cmd_evt_handler(ipcc: &mut Ipcc) -> CcEvt {
 | 
			
		||||
        ipcc.c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false);
 | 
			
		||||
 | 
			
		||||
        // ST's command response data structure is really convoluted.
 | 
			
		||||
        //
 | 
			
		||||
        // for command response events on SYS channel, the header is missing
 | 
			
		||||
        // and one should:
 | 
			
		||||
        // 1. interpret the content of CMD_BUFFER as CmdPacket
 | 
			
		||||
        // 2. Access CmdPacket's cmdserial field and interpret its content as EvtSerial
 | 
			
		||||
        // 3. Access EvtSerial's evt field (as Evt) and interpret its payload as CcEvt
 | 
			
		||||
        // 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 evt_serial: *const EvtSerial = cmd_serial.cast();
 | 
			
		||||
            let cc = (*evt_serial).evt.payload.as_ptr().cast();
 | 
			
		||||
            *cc
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[allow(dead_code)]
 | 
			
		||||
    pub(crate) fn send_cmd(ipcc: &mut Ipcc, buf: &[u8]) {
 | 
			
		||||
        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();
 | 
			
		||||
 | 
			
		||||
            core::ptr::copy(buf.as_ptr(), cmd_serial_buf, buf.len());
 | 
			
		||||
 | 
			
		||||
            let mut cmd_packet = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer;
 | 
			
		||||
            cmd_packet.cmd_serial.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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::ipcc::{Config, Ipcc};
 | 
			
		||||
use embassy_stm32::tl_mbox::TlMbox;
 | 
			
		||||
use embassy_time::{Duration, Timer};
 | 
			
		||||
@@ -40,7 +41,10 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut ipcc = Ipcc::new(p.IPCC, config);
 | 
			
		||||
 | 
			
		||||
    let mbox = TlMbox::init(&mut ipcc);
 | 
			
		||||
    let rx_irq = interrupt::take!(IPCC_C1_RX);
 | 
			
		||||
    let tx_irq = interrupt::take!(IPCC_C1_TX);
 | 
			
		||||
 | 
			
		||||
    let mbox = TlMbox::init(&mut ipcc, rx_irq, tx_irq);
 | 
			
		||||
 | 
			
		||||
    loop {
 | 
			
		||||
        let wireless_fw_info = mbox.wireless_fw_info();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										96
									
								
								examples/stm32wb/src/bin/tl_mbox_tx_rx.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								examples/stm32wb/src/bin/tl_mbox_tx_rx.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
#![no_std]
 | 
			
		||||
#![no_main]
 | 
			
		||||
#![feature(type_alias_impl_trait)]
 | 
			
		||||
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::interrupt;
 | 
			
		||||
use embassy_stm32::ipcc::{Config, Ipcc};
 | 
			
		||||
use embassy_stm32::tl_mbox::TlMbox;
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
 | 
			
		||||
#[embassy_executor::main]
 | 
			
		||||
async fn main(_spawner: Spawner) {
 | 
			
		||||
    /*
 | 
			
		||||
        How to make this work:
 | 
			
		||||
 | 
			
		||||
        - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
 | 
			
		||||
        - Download and Install STM32CubeProgrammer.
 | 
			
		||||
        - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
 | 
			
		||||
          gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
 | 
			
		||||
        - Open STM32CubeProgrammer
 | 
			
		||||
        - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
 | 
			
		||||
        - Once complete, click connect to connect to the device.
 | 
			
		||||
        - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
 | 
			
		||||
        - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
 | 
			
		||||
        - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
 | 
			
		||||
        - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
 | 
			
		||||
          stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
 | 
			
		||||
        - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
 | 
			
		||||
        - Disconnect from the device.
 | 
			
		||||
        - In the examples folder for stm32wb, modify the memory.x file to match your target device.
 | 
			
		||||
        - Run this example.
 | 
			
		||||
 | 
			
		||||
        Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    let p = embassy_stm32::init(Default::default());
 | 
			
		||||
    info!("Hello World!");
 | 
			
		||||
 | 
			
		||||
    let config = Config::default();
 | 
			
		||||
    let mut ipcc = Ipcc::new(p.IPCC, config);
 | 
			
		||||
 | 
			
		||||
    let rx_irq = interrupt::take!(IPCC_C1_RX);
 | 
			
		||||
    let tx_irq = interrupt::take!(IPCC_C1_TX);
 | 
			
		||||
 | 
			
		||||
    let mbox = TlMbox::init(&mut ipcc, rx_irq, tx_irq);
 | 
			
		||||
 | 
			
		||||
    // initialize ble stack, does not return a response
 | 
			
		||||
    // mbox.shci_ble_init(&mut ipcc, Default::default());
 | 
			
		||||
 | 
			
		||||
    info!("waiting for coprocessor to boot");
 | 
			
		||||
    let event_box = mbox.read().await;
 | 
			
		||||
 | 
			
		||||
    let mut payload = [0u8; 6];
 | 
			
		||||
    event_box.copy_into_slice(&mut payload).unwrap();
 | 
			
		||||
 | 
			
		||||
    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..]
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mbox.shci_ble_init(&mut ipcc, Default::default());
 | 
			
		||||
 | 
			
		||||
    info!("resetting BLE");
 | 
			
		||||
    mbox.send_ble_cmd(&mut ipcc, &[0x01, 0x03, 0x0c]);
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    loop {}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user