Merge #1457
1457: TL Mbox read and write for stm32wb r=xoviat a=OueslatiGhaith Hello, This pull request is related to #1397 and #1401, inspired by #24, built upon the work done in #1405 and #1424, and was tested on an stm32wb55rg. This pull request aims to add read and write functionality to the TL mailbox for stm32wb microcontrollers Co-authored-by: goueslati <ghaith.oueslati@habemus.com> Co-authored-by: xoviat <xoviat@users.noreply.github.com>
This commit is contained in:
commit
1fdde8f03f
@ -35,6 +35,10 @@ pub struct Ipcc<'d> {
|
|||||||
|
|
||||||
impl<'d> Ipcc<'d> {
|
impl<'d> Ipcc<'d> {
|
||||||
pub fn new(peri: impl Peripheral<P = IPCC> + 'd, _config: Config) -> Self {
|
pub fn new(peri: impl Peripheral<P = IPCC> + 'd, _config: Config) -> Self {
|
||||||
|
Self::new_inner(peri)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_inner(peri: impl Peripheral<P = IPCC> + 'd) -> Self {
|
||||||
into_ref!(peri);
|
into_ref!(peri);
|
||||||
|
|
||||||
Self { _peri: peri }
|
Self { _peri: peri }
|
||||||
@ -158,6 +162,10 @@ impl<'d> Ipcc<'d> {
|
|||||||
pub fn is_rx_pending(&self, channel: IpccChannel) -> bool {
|
pub fn is_rx_pending(&self, channel: IpccChannel) -> bool {
|
||||||
self.c2_is_active_flag(channel) && self.c1_get_rx_channel(channel)
|
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 {
|
impl sealed::Instance for crate::peripherals::IPCC {
|
||||||
|
@ -1,15 +1,24 @@
|
|||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
use super::unsafe_linked_list::LST_init_head;
|
use embassy_futures::block_on;
|
||||||
use super::{channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE};
|
|
||||||
|
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 crate::ipcc::Ipcc;
|
use crate::ipcc::Ipcc;
|
||||||
|
use crate::tl_mbox::cmd::CmdPacket;
|
||||||
|
|
||||||
pub struct Ble;
|
pub struct Ble;
|
||||||
|
|
||||||
impl Ble {
|
impl Ble {
|
||||||
pub fn new(ipcc: &mut Ipcc) -> Self {
|
pub(crate) fn new(ipcc: &mut Ipcc) -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
LST_init_head(EVT_QUEUE.as_mut_ptr());
|
LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
|
||||||
|
|
||||||
TL_BLE_TABLE = MaybeUninit::new(BleTable {
|
TL_BLE_TABLE = MaybeUninit::new(BleTable {
|
||||||
pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(),
|
pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(),
|
||||||
@ -23,4 +32,37 @@ impl Ble {
|
|||||||
|
|
||||||
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 !LinkedListNode::is_empty(EVT_QUEUE.as_mut_ptr()) {
|
||||||
|
LinkedListNode::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 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 {
|
pub mod cpu1 {
|
||||||
use crate::ipcc::IpccChannel;
|
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;
|
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;
|
pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
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;
|
pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
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;
|
pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
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
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[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
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4;
|
pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[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
|
/// the payload of [`Evt`] for a command status event
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
@ -6,3 +13,127 @@ pub struct CsEvt {
|
|||||||
pub num_cmd: u8,
|
pub num_cmd: u8,
|
||||||
pub cmd_code: u16,
|
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, ()> {
|
||||||
|
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::Ipcc;
|
||||||
|
|
||||||
|
let mut ipcc = Ipcc::new_inner(unsafe { crate::Peripherals::steal() }.IPCC);
|
||||||
|
mm::MemoryManager::evt_drop(self.ptr, &mut ipcc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
use super::unsafe_linked_list::LST_init_head;
|
use super::evt::EvtPacket;
|
||||||
|
use super::unsafe_linked_list::LinkedListNode;
|
||||||
use super::{
|
use super::{
|
||||||
MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, SYS_SPARE_EVT_BUF,
|
channels, MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE,
|
||||||
TL_MEM_MANAGER_TABLE,
|
SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE, TL_REF_TABLE,
|
||||||
};
|
};
|
||||||
|
use crate::ipcc::Ipcc;
|
||||||
|
|
||||||
pub struct MemoryManager;
|
pub struct MemoryManager;
|
||||||
|
|
||||||
impl MemoryManager {
|
impl MemoryManager {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
LST_init_head(FREE_BUFF_QUEUE.as_mut_ptr());
|
LinkedListNode::init_head(FREE_BUFF_QUEUE.as_mut_ptr());
|
||||||
LST_init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
|
LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
|
||||||
|
|
||||||
TL_MEM_MANAGER_TABLE = MaybeUninit::new(MemManagerTable {
|
TL_MEM_MANAGER_TABLE = MaybeUninit::new(MemManagerTable {
|
||||||
spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
|
spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
|
||||||
@ -27,4 +29,43 @@ impl MemoryManager {
|
|||||||
|
|
||||||
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();
|
||||||
|
|
||||||
|
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,20 +1,27 @@
|
|||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
use bit_field::BitField;
|
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::ble::Ble;
|
||||||
use self::cmd::{AclDataPacket, CmdPacket};
|
use self::cmd::{AclDataPacket, CmdPacket};
|
||||||
use self::evt::CsEvt;
|
use self::evt::{CsEvt, EvtBox};
|
||||||
use self::mm::MemoryManager;
|
use self::mm::MemoryManager;
|
||||||
|
use self::shci::{shci_ble_init, ShciBleInitCmdParam};
|
||||||
use self::sys::Sys;
|
use self::sys::Sys;
|
||||||
use self::unsafe_linked_list::LinkedListNode;
|
use self::unsafe_linked_list::LinkedListNode;
|
||||||
|
use crate::_generated::interrupt::{IPCC_C1_RX, IPCC_C1_TX};
|
||||||
use crate::ipcc::Ipcc;
|
use crate::ipcc::Ipcc;
|
||||||
|
|
||||||
mod ble;
|
mod ble;
|
||||||
mod channels;
|
mod channels;
|
||||||
mod cmd;
|
mod cmd;
|
||||||
|
mod consts;
|
||||||
mod evt;
|
mod evt;
|
||||||
mod mm;
|
mod mm;
|
||||||
|
mod shci;
|
||||||
mod sys;
|
mod sys;
|
||||||
mod unsafe_linked_list;
|
mod unsafe_linked_list;
|
||||||
|
|
||||||
@ -42,10 +49,10 @@ pub struct SafeBootInfoTable {
|
|||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct RssInfoTable {
|
pub struct FusInfoTable {
|
||||||
version: u32,
|
version: u32,
|
||||||
memory_size: u32,
|
memory_size: u32,
|
||||||
rss_info: u32,
|
fus_info: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Version
|
/// # Version
|
||||||
@ -64,8 +71,8 @@ pub struct RssInfoTable {
|
|||||||
pub struct WirelessFwInfoTable {
|
pub struct WirelessFwInfoTable {
|
||||||
version: u32,
|
version: u32,
|
||||||
memory_size: u32,
|
memory_size: u32,
|
||||||
thread_info: u32,
|
info_stack: u32,
|
||||||
ble_info: u32,
|
reserved: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WirelessFwInfoTable {
|
impl WirelessFwInfoTable {
|
||||||
@ -107,7 +114,7 @@ impl WirelessFwInfoTable {
|
|||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct DeviceInfoTable {
|
pub struct DeviceInfoTable {
|
||||||
pub safe_boot_info_table: SafeBootInfoTable,
|
pub safe_boot_info_table: SafeBootInfoTable,
|
||||||
pub rss_info_table: RssInfoTable,
|
pub fus_info_table: FusInfoTable,
|
||||||
pub wireless_fw_info_table: WirelessFwInfoTable,
|
pub wireless_fw_info_table: WirelessFwInfoTable,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,6 +198,9 @@ pub struct RefTable {
|
|||||||
mem_manager_table: *const MemManagerTable,
|
mem_manager_table: *const MemManagerTable,
|
||||||
traces_table: *const TracesTable,
|
traces_table: *const TracesTable,
|
||||||
mac_802_15_4_table: *const Mac802_15_4Table,
|
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"]
|
#[link_section = "TL_REF_TABLE"]
|
||||||
@ -205,6 +215,12 @@ static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit();
|
|||||||
#[link_section = "MB_MEM1"]
|
#[link_section = "MB_MEM1"]
|
||||||
static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit();
|
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"]
|
#[link_section = "MB_MEM1"]
|
||||||
static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit();
|
static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit();
|
||||||
|
|
||||||
@ -217,17 +233,16 @@ static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit();
|
|||||||
#[link_section = "MB_MEM1"]
|
#[link_section = "MB_MEM1"]
|
||||||
static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit();
|
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
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
#[link_section = "MB_MEM2"]
|
#[link_section = "MB_MEM1"]
|
||||||
static mut FREE_BUFF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
static mut FREE_BUFF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||||
|
|
||||||
// not in shared RAM
|
// not in shared RAM
|
||||||
static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
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();
|
|
||||||
|
|
||||||
#[link_section = "MB_MEM2"]
|
#[link_section = "MB_MEM2"]
|
||||||
static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> =
|
static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> =
|
||||||
MaybeUninit::uninit();
|
MaybeUninit::uninit();
|
||||||
@ -259,6 +274,9 @@ static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
|
|||||||
// "magic" numbers from ST ---v---v
|
// "magic" numbers from ST ---v---v
|
||||||
static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit();
|
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 {
|
pub struct TlMbox {
|
||||||
_sys: Sys,
|
_sys: Sys,
|
||||||
_ble: Ble,
|
_ble: Ble,
|
||||||
@ -267,7 +285,7 @@ pub struct TlMbox {
|
|||||||
|
|
||||||
impl TlMbox {
|
impl TlMbox {
|
||||||
/// initializes low-level transport between CPU1 and BLE stack on CPU2
|
/// 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 {
|
unsafe {
|
||||||
TL_REF_TABLE = MaybeUninit::new(RefTable {
|
TL_REF_TABLE = MaybeUninit::new(RefTable {
|
||||||
device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
|
device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
|
||||||
@ -277,6 +295,9 @@ impl TlMbox {
|
|||||||
mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
|
mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
|
||||||
traces_table: TL_TRACES_TABLE.as_ptr(),
|
traces_table: TL_TRACES_TABLE.as_ptr(),
|
||||||
mac_802_15_4_table: TL_MAC_802_15_4_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(),
|
||||||
});
|
});
|
||||||
|
|
||||||
TL_SYS_TABLE = MaybeUninit::zeroed();
|
TL_SYS_TABLE = MaybeUninit::zeroed();
|
||||||
@ -286,6 +307,9 @@ impl TlMbox {
|
|||||||
TL_MEM_MANAGER_TABLE = MaybeUninit::zeroed();
|
TL_MEM_MANAGER_TABLE = MaybeUninit::zeroed();
|
||||||
TL_TRACES_TABLE = MaybeUninit::zeroed();
|
TL_TRACES_TABLE = MaybeUninit::zeroed();
|
||||||
TL_MAC_802_15_4_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();
|
EVT_POOL = MaybeUninit::zeroed();
|
||||||
SYS_SPARE_EVT_BUF = MaybeUninit::zeroed();
|
SYS_SPARE_EVT_BUF = MaybeUninit::zeroed();
|
||||||
@ -302,6 +326,24 @@ impl TlMbox {
|
|||||||
let _ble = Ble::new(ipcc);
|
let _ble = Ble::new(ipcc);
|
||||||
let _mm = MemoryManager::new();
|
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 }
|
TlMbox { _sys, _ble, _mm }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,4 +357,41 @@ impl TlMbox {
|
|||||||
None
|
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 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,15 +1,20 @@
|
|||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
use super::unsafe_linked_list::LST_init_head;
|
use embassy_futures::block_on;
|
||||||
use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_SYS_TABLE};
|
|
||||||
|
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::ipcc::Ipcc;
|
use crate::ipcc::Ipcc;
|
||||||
|
|
||||||
pub struct Sys;
|
pub struct Sys;
|
||||||
|
|
||||||
impl Sys {
|
impl Sys {
|
||||||
pub fn new(ipcc: &mut Ipcc) -> Self {
|
pub(crate) fn new(ipcc: &mut Ipcc) -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
LST_init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
|
LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
|
||||||
|
|
||||||
TL_SYS_TABLE = MaybeUninit::new(SysTable {
|
TL_SYS_TABLE = MaybeUninit::new(SysTable {
|
||||||
pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
|
pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
|
||||||
@ -21,4 +26,62 @@ impl Sys {
|
|||||||
|
|
||||||
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 !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(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 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,95 +29,97 @@ impl Default for LinkedListNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn LST_init_head(mut listHead: *mut LinkedListNode) {
|
impl LinkedListNode {
|
||||||
(*listHead).next = listHead;
|
pub unsafe fn init_head(mut list_head: *mut LinkedListNode) {
|
||||||
(*listHead).prev = listHead;
|
(*list_head).next = list_head;
|
||||||
}
|
(*list_head).prev = list_head;
|
||||||
|
}
|
||||||
pub unsafe fn LST_is_empty(mut listHead: *mut LinkedListNode) -> bool {
|
|
||||||
interrupt::free(|_| ((*listHead).next) == listHead)
|
pub unsafe fn is_empty(mut list_head: *mut LinkedListNode) -> bool {
|
||||||
}
|
interrupt::free(|_| ((*list_head).next) == list_head)
|
||||||
|
}
|
||||||
pub unsafe fn LST_insert_head(mut listHead: *mut LinkedListNode, mut node: *mut LinkedListNode) {
|
|
||||||
interrupt::free(|_| {
|
pub unsafe fn insert_head(mut list_head: *mut LinkedListNode, mut node: *mut LinkedListNode) {
|
||||||
(*node).next = (*listHead).next;
|
interrupt::free(|_| {
|
||||||
(*node).prev = listHead;
|
(*node).next = (*list_head).next;
|
||||||
(*listHead).next = node;
|
(*node).prev = list_head;
|
||||||
(*(*node).next).prev = node;
|
(*list_head).next = node;
|
||||||
});
|
(*(*node).next).prev = node;
|
||||||
}
|
});
|
||||||
|
}
|
||||||
pub unsafe fn LST_insert_tail(mut listHead: *mut LinkedListNode, mut node: *mut LinkedListNode) {
|
|
||||||
interrupt::free(|_| {
|
pub unsafe fn insert_tail(mut list_head: *mut LinkedListNode, mut node: *mut LinkedListNode) {
|
||||||
(*node).next = listHead;
|
interrupt::free(|_| {
|
||||||
(*node).prev = (*listHead).prev;
|
(*node).next = list_head;
|
||||||
(*listHead).prev = node;
|
(*node).prev = (*list_head).prev;
|
||||||
(*(*node).prev).next = node;
|
(*list_head).prev = node;
|
||||||
});
|
(*(*node).prev).next = node;
|
||||||
}
|
});
|
||||||
|
}
|
||||||
pub unsafe fn LST_remove_node(mut node: *mut LinkedListNode) {
|
|
||||||
interrupt::free(|_| {
|
pub unsafe fn remove_node(mut node: *mut LinkedListNode) {
|
||||||
(*(*node).prev).next = (*node).next;
|
interrupt::free(|_| {
|
||||||
(*(*node).next).prev = (*node).prev;
|
(*(*node).prev).next = (*node).next;
|
||||||
});
|
(*(*node).next).prev = (*node).prev;
|
||||||
}
|
});
|
||||||
|
}
|
||||||
pub unsafe fn LST_remove_head(mut listHead: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
|
|
||||||
interrupt::free(|_| {
|
pub unsafe fn remove_head(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
|
||||||
*node = (*listHead).next;
|
interrupt::free(|_| {
|
||||||
LST_remove_node((*listHead).next);
|
*node = (*list_head).next;
|
||||||
});
|
Self::remove_node((*list_head).next);
|
||||||
}
|
});
|
||||||
|
}
|
||||||
pub unsafe fn LST_remove_tail(mut listHead: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
|
|
||||||
interrupt::free(|_| {
|
pub unsafe fn remove_tail(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
|
||||||
*node = (*listHead).prev;
|
interrupt::free(|_| {
|
||||||
LST_remove_node((*listHead).prev);
|
*node = (*list_head).prev;
|
||||||
});
|
Self::remove_node((*list_head).prev);
|
||||||
}
|
});
|
||||||
|
}
|
||||||
pub unsafe fn LST_insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
|
|
||||||
interrupt::free(|_| {
|
pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
|
||||||
(*node).next = (*ref_node).next;
|
interrupt::free(|_| {
|
||||||
(*node).prev = ref_node;
|
(*node).next = (*ref_node).next;
|
||||||
(*ref_node).next = node;
|
(*node).prev = ref_node;
|
||||||
(*(*node).next).prev = node;
|
(*ref_node).next = node;
|
||||||
});
|
(*(*node).next).prev = node;
|
||||||
}
|
});
|
||||||
|
}
|
||||||
pub unsafe fn LST_insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
|
|
||||||
interrupt::free(|_| {
|
pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
|
||||||
(*node).next = ref_node;
|
interrupt::free(|_| {
|
||||||
(*node).prev = (*ref_node).prev;
|
(*node).next = ref_node;
|
||||||
(*ref_node).prev = node;
|
(*node).prev = (*ref_node).prev;
|
||||||
(*(*node).prev).next = node;
|
(*ref_node).prev = node;
|
||||||
});
|
(*(*node).prev).next = node;
|
||||||
}
|
});
|
||||||
|
}
|
||||||
pub unsafe fn LST_get_size(mut listHead: *mut LinkedListNode) -> usize {
|
|
||||||
interrupt::free(|_| {
|
pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize {
|
||||||
let mut size = 0;
|
interrupt::free(|_| {
|
||||||
let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
|
let mut size = 0;
|
||||||
|
let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
|
||||||
temp = (*listHead).next;
|
|
||||||
while temp != listHead {
|
temp = (*list_head).next;
|
||||||
size += 1;
|
while temp != list_head {
|
||||||
temp = (*temp).next
|
size += 1;
|
||||||
}
|
temp = (*temp).next
|
||||||
|
}
|
||||||
size
|
|
||||||
})
|
size
|
||||||
}
|
})
|
||||||
|
}
|
||||||
pub unsafe fn LST_get_next_node(mut ref_node: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
|
|
||||||
interrupt::free(|_| {
|
pub unsafe fn get_next_node(mut ref_node: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
|
||||||
*node = (*ref_node).next;
|
interrupt::free(|_| {
|
||||||
});
|
*node = (*ref_node).next;
|
||||||
}
|
});
|
||||||
|
}
|
||||||
pub unsafe fn LST_get_prev_node(mut ref_node: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
|
|
||||||
interrupt::free(|_| {
|
pub unsafe fn get_prev_node(mut ref_node: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
|
||||||
*node = (*ref_node).prev;
|
interrupt::free(|_| {
|
||||||
});
|
*node = (*ref_node).prev;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ MEMORY
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Memory size for STM32WB55xC with 512K FLASH
|
Memory size for STM32WB55xG with 512K FLASH
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_stm32::interrupt;
|
||||||
use embassy_stm32::ipcc::{Config, Ipcc};
|
use embassy_stm32::ipcc::{Config, Ipcc};
|
||||||
use embassy_stm32::tl_mbox::TlMbox;
|
use embassy_stm32::tl_mbox::TlMbox;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
@ -27,6 +28,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
- Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
|
- 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.
|
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".
|
- Select that file, the memory address, "verify download", and then "Firmware Upgrade".
|
||||||
|
- Select "Start Wireless Stack".
|
||||||
- Disconnect from the device.
|
- Disconnect from the device.
|
||||||
- In the examples folder for stm32wb, modify the memory.x file to match your target device.
|
- In the examples folder for stm32wb, modify the memory.x file to match your target device.
|
||||||
- Run this example.
|
- Run this example.
|
||||||
@ -40,7 +42,10 @@ async fn main(_spawner: Spawner) {
|
|||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let mut ipcc = Ipcc::new(p.IPCC, config);
|
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 {
|
loop {
|
||||||
let wireless_fw_info = mbox.wireless_fw_info();
|
let wireless_fw_info = mbox.wireless_fw_info();
|
||||||
|
97
examples/stm32wb/src/bin/tl_mbox_tx_rx.rs
Normal file
97
examples/stm32wb/src/bin/tl_mbox_tx_rx.rs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#![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".
|
||||||
|
- Select "Start Wireless Stack".
|
||||||
|
- 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, 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
|
||||||
|
);
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
}
|
@ -12,6 +12,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
if cfg!(any(feature = "stm32f103c8", feature = "stm32c031c6")) {
|
if cfg!(any(feature = "stm32f103c8", feature = "stm32c031c6")) {
|
||||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||||
println!("cargo:rerun-if-changed=link.x");
|
println!("cargo:rerun-if-changed=link.x");
|
||||||
|
} else if cfg!(feature = "stm32wb55rg") {
|
||||||
|
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||||
|
fs::write(out.join("memory.x"), include_bytes!("memory_ble.x")).unwrap();
|
||||||
} else {
|
} else {
|
||||||
println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
|
println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
|
||||||
println!("cargo:rerun-if-changed=link_ram.x");
|
println!("cargo:rerun-if-changed=link_ram.x");
|
||||||
|
23
tests/stm32/memory_ble.x
Normal file
23
tests/stm32/memory_ble.x
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
Memory size for STM32WB55xG with 512K FLASH
|
||||||
|
*/
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
|
||||||
|
RAM (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8
|
||||||
|
RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Place stack at the end of SRAM1 */
|
||||||
|
_stack_start = ORIGIN(RAM) + LENGTH(RAM);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scatter the mailbox interface memory sections in shared memory
|
||||||
|
*/
|
||||||
|
SECTIONS {
|
||||||
|
TL_REF_TABLE (NOLOAD) : { *(TL_REF_TABLE) } >RAM_SHARED
|
||||||
|
|
||||||
|
MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED
|
||||||
|
MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED
|
||||||
|
}
|
@ -7,6 +7,7 @@
|
|||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
mod example_common;
|
mod example_common;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_stm32::interrupt;
|
||||||
use embassy_stm32::ipcc::{Config, Ipcc};
|
use embassy_stm32::ipcc::{Config, Ipcc};
|
||||||
use embassy_stm32::tl_mbox::TlMbox;
|
use embassy_stm32::tl_mbox::TlMbox;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
@ -20,12 +21,15 @@ async fn main(_spawner: Spawner) {
|
|||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let mut ipcc = Ipcc::new(p.IPCC, config);
|
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 {
|
loop {
|
||||||
let wireless_fw_info = mbox.wireless_fw_info();
|
let wireless_fw_info = mbox.wireless_fw_info();
|
||||||
match wireless_fw_info {
|
match wireless_fw_info {
|
||||||
None => error!("not yet initialized"),
|
None => {}
|
||||||
Some(fw_info) => {
|
Some(fw_info) => {
|
||||||
let version_major = fw_info.version_major();
|
let version_major = fw_info.version_major();
|
||||||
let version_minor = fw_info.version_minor();
|
let version_minor = fw_info.version_minor();
|
||||||
@ -43,7 +47,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(500)).await;
|
Timer::after(Duration::from_millis(50)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Test OK");
|
info!("Test OK");
|
||||||
|
Loading…
Reference in New Issue
Block a user