From abbaaeee378f41ddf9f1a3c40777be3572680484 Mon Sep 17 00:00:00 2001 From: goueslati Date: Thu, 25 May 2023 16:39:43 +0100 Subject: [PATCH 01/15] stm32/ipcc: support for MAC 802.15.4 --- embassy-stm32/Cargo.toml | 10 ++ embassy-stm32/src/tl_mbox/ble.rs | 23 +++- embassy-stm32/src/tl_mbox/channels.rs | 146 ++++++++++++++-------- embassy-stm32/src/tl_mbox/mac_802_15_4.rs | 82 ++++++++++++ embassy-stm32/src/tl_mbox/mm.rs | 12 +- embassy-stm32/src/tl_mbox/mod.rs | 115 ++++++++++++----- embassy-stm32/src/tl_mbox/shci.rs | 4 +- embassy-stm32/src/tl_mbox/sys.rs | 16 ++- 8 files changed, 306 insertions(+), 102 deletions(-) create mode 100644 embassy-stm32/src/tl_mbox/mac_802_15_4.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 21adb5dd..c2b0a3ec 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -110,6 +110,16 @@ unstable-pac = [] # Implement embedded-hal-async traits if `nightly` is set as well. unstable-traits = ["embedded-hal-1", "dep:embedded-hal-nb"] +# stm32wb specific +# support for wireless stacks +ble = [] +thread = [] +lld-tests = [] +ble-lld = [] +mac-802_15_4 = [] +zigbee = [] +traces = [] + # Chip-selection features stm32c011d6 = [ "stm32-metapac/stm32c011d6" ] stm32c011f4 = [ "stm32-metapac/stm32c011f4" ] diff --git a/embassy-stm32/src/tl_mbox/ble.rs b/embassy-stm32/src/tl_mbox/ble.rs index d8bf14d4..21688ff4 100644 --- a/embassy-stm32/src/tl_mbox/ble.rs +++ b/embassy-stm32/src/tl_mbox/ble.rs @@ -16,7 +16,7 @@ use crate::tl_mbox::cmd::CmdPacket; pub struct Ble; impl Ble { - pub(crate) fn new(ipcc: &mut Ipcc) -> Self { + pub(crate) fn init(ipcc: &mut Ipcc) -> Self { unsafe { LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); @@ -28,7 +28,7 @@ impl Ble { }); } - ipcc.c1_set_rx_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, true); + ipcc.c1_set_rx_channel(channels::Cpu2Channel::BleEvent.into(), true); Ble } @@ -48,7 +48,11 @@ impl Ble { } } - ipcc.c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL); + ipcc.c1_clear_flag_channel(channels::Cpu2Channel::BleEvent.into()); + } + + pub(crate) fn acl_data_evt_handler(ipcc: &mut Ipcc) { + ipcc.c1_set_tx_channel(channels::Cpu1Channel::HciAclData.into(), false); } pub(crate) fn send_cmd(ipcc: &mut Ipcc, buf: &[u8]) { @@ -63,6 +67,17 @@ impl Ble { cmd_packet.cmd_serial.ty = TlPacketType::BleCmd as u8; } - ipcc.c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL); + ipcc.c1_set_flag_channel(channels::Cpu1Channel::BleCmd.into()); + } + + pub(crate) fn send_acl_data(ipcc: &mut Ipcc) { + unsafe { + (*(*TL_REF_TABLE.assume_init().ble_table).phci_acl_data_buffer) + .acl_data_serial + .ty = TlPacketType::AclData as u8; + } + + ipcc.c1_set_flag_channel(channels::Cpu1Channel::HciAclData.into()); + ipcc.c1_set_tx_channel(channels::Cpu1Channel::HciAclData.into(), true); } } diff --git a/embassy-stm32/src/tl_mbox/channels.rs b/embassy-stm32/src/tl_mbox/channels.rs index aaa6ce17..94e97230 100644 --- a/embassy-stm32/src/tl_mbox/channels.rs +++ b/embassy-stm32/src/tl_mbox/channels.rs @@ -49,56 +49,104 @@ //! | | //! -pub mod cpu1 { - use crate::ipcc::IpccChannel; +use crate::ipcc::IpccChannel; - // Not used currently but reserved - pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1; - // Not used currently but reserved - pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; - // Not used currently but reserved - pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6; +pub enum Cpu1Channel { + BleCmd, + SystemCmdRsp, + #[cfg(feature = "thread")] + ThreadOtCmdRsp, + #[cfg(feature = "zigbee")] + ZigbeeCmdAppli, + MmReleaseBuffer, + #[cfg(feature = "mac-802_15_4")] + Mac802_15_4cmdRsp, + #[cfg(feature = "thread")] + ThreadCliCmd, + #[cfg(feature = "lld-tests")] + LldTestsCliCmd, + #[cfg(feature = "ble-lld")] + BleLldCmd, + HciAclData, } -pub mod cpu2 { - use crate::ipcc::IpccChannel; - - pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1; - pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_BLE_LLD_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_BLE_LLD_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_BLE_LLD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5; - #[allow(dead_code)] // Not used currently but reserved - pub const IPCC_ZIGBEE_M0_REQUEST_CHANNEL: IpccChannel = IpccChannel::Channel5; +impl From for IpccChannel { + fn from(value: Cpu1Channel) -> Self { + match value { + Cpu1Channel::BleCmd => IpccChannel::Channel1, + Cpu1Channel::SystemCmdRsp => IpccChannel::Channel2, + #[cfg(feature = "thread")] + Cpu1Channel::ThreadOtCmdRsp => IpccChannel::Channel3, + #[cfg(feature = "zigbee")] + Cpu1Channel::ZigbeeCmdAppli => IpccChannel::Channel3, + #[cfg(feature = "mac-802_15_4")] + Cpu1Channel::Mac802_15_4cmdRsp => IpccChannel::Channel3, + Cpu1Channel::MmReleaseBuffer => IpccChannel::Channel4, + #[cfg(feature = "thread")] + Cpu1Channel::ThreadCliCmd => IpccChannel::Channel5, + #[cfg(feature = "lld-tests")] + Cpu1Channel::LldTestsCliCmd => IpccChannel::Channel5, + #[cfg(feature = "ble-lld")] + Cpu1Channel::BleLldCmd => IpccChannel::Channel5, + Cpu1Channel::HciAclData => IpccChannel::Channel6, + } + } +} + +pub enum Cpu2Channel { + BleEvent, + SystemEvent, + #[cfg(feature = "thread")] + ThreadNotifAck, + #[cfg(feature = "zigbee")] + ZigbeeAppliNotifAck, + #[cfg(feature = "mac-802_15_4")] + Mac802_15_4NotifAck, + #[cfg(feature = "lld-tests")] + LldTestsM0Cmd, + #[cfg(feature = "ble-lld")] + BleLldM0Cmd, + #[cfg(feature = "traces")] + Traces, + #[cfg(feature = "thread")] + ThreadCliNotifAck, + #[cfg(feature = "lld-tests")] + LldTestsCliRsp, + #[cfg(feature = "ble-lld")] + BleLldCliRsp, + #[cfg(feature = "ble-lld")] + BleLldRsp, + #[cfg(feature = "zigbee")] + ZigbeeM0Request, +} + +impl From for IpccChannel { + fn from(value: Cpu2Channel) -> Self { + match value { + Cpu2Channel::BleEvent => IpccChannel::Channel1, + Cpu2Channel::SystemEvent => IpccChannel::Channel2, + #[cfg(feature = "thread")] + Cpu2Channel::ThreadNotifAck => IpccChannel::Channel3, + #[cfg(feature = "zigbee")] + Cpu2Channel::ZigbeeAppliNotifAck => IpccChannel::Channel3, + #[cfg(feature = "mac-802_15_4")] + Cpu2Channel::Mac802_15_4NotifAck => IpccChannel::Channel3, + #[cfg(feature = "lld-tests")] + Cpu2Channel::LldTestsM0Cmd => IpccChannel::Channel3, + #[cfg(feature = "ble-lld")] + Cpu2Channel::BleLldM0Cmd => IpccChannel::Channel3, + #[cfg(feature = "traces")] + Cpu2Channel::Traces => IpccChannel::Channel4, + #[cfg(feature = "thread")] + Cpu2Channel::ThreadCliNotifAck => IpccChannel::Channel5, + #[cfg(feature = "lld-tests")] + Cpu2Channel::LldTestsCliRsp => IpccChannel::Channel5, + #[cfg(feature = "ble-lld")] + Cpu2Channel::BleLldCliRsp => IpccChannel::Channel5, + #[cfg(feature = "ble-lld")] + Cpu2Channel::BleLldRsp => IpccChannel::Channel5, + #[cfg(feature = "zigbee")] + Cpu2Channel::ZigbeeM0Request => IpccChannel::Channel5, + } + } } diff --git a/embassy-stm32/src/tl_mbox/mac_802_15_4.rs b/embassy-stm32/src/tl_mbox/mac_802_15_4.rs new file mode 100644 index 00000000..19f95113 --- /dev/null +++ b/embassy-stm32/src/tl_mbox/mac_802_15_4.rs @@ -0,0 +1,82 @@ +use core::mem::MaybeUninit; + +use embassy_futures::block_on; + +use super::cmd::{CmdPacket, CmdSerial}; +use super::consts::TlPacketType; +use super::evt::{EvtBox, EvtPacket}; +use super::unsafe_linked_list::LinkedListNode; +use super::{ + channels, Mac802_15_4Table, EVT_QUEUE, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, TL_CHANNEL, + TL_MAC_802_15_4_TABLE, TL_REF_TABLE, +}; +use crate::ipcc::Ipcc; + +pub struct Mac802_15_4; + +impl Mac802_15_4 { + pub(crate) fn init(ipcc: &mut Ipcc) -> Self { + unsafe { + LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); + + TL_MAC_802_15_4_TABLE = MaybeUninit::new(Mac802_15_4Table { + pcmd_rsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(), + pnotack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(), + evt_queue: EVT_QUEUE.as_ptr().cast(), + }); + } + + ipcc.c1_set_rx_channel(channels::Cpu2Channel::Mac802_15_4NotifAck.into(), true); + + Self + } + + pub(crate) fn notif_evt_handler(ipcc: &mut Ipcc) { + unsafe { + let notif_buffer: *mut EvtPacket = (*TL_REF_TABLE.assume_init().mac_802_15_4_table).pnotack_buffer.cast(); + let event = EvtBox::new(notif_buffer); + + block_on(TL_CHANNEL.send(event)); + } + + ipcc.c1_set_rx_channel(channels::Cpu2Channel::Mac802_15_4NotifAck.into(), false); + } + + pub(crate) fn cmd_evt_handler(ipcc: &mut Ipcc) { + unsafe { + let _notif_buffer = (*TL_REF_TABLE.assume_init().mac_802_15_4_table).pcmd_rsp_buffer; + + // NOTE: ST's HAL does nothing with this buffer, ?????? + } + + ipcc.c1_set_tx_channel(channels::Cpu1Channel::Mac802_15_4cmdRsp.into(), false); + } + + pub(crate) fn send_cmd(ipcc: &mut Ipcc, buf: &[u8]) { + unsafe { + let pcmd_buffer: *mut CmdPacket = (*TL_REF_TABLE.assume_init().mac_802_15_4_table).pcmd_rsp_buffer.cast(); + 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 CmdPacket = + &mut *(*TL_REF_TABLE.assume_init().mac_802_15_4_table).pcmd_rsp_buffer.cast(); + cmd_packet.cmd_serial.ty = TlPacketType::OtCmd as u8; + } + + ipcc.c1_set_flag_channel(channels::Cpu1Channel::Mac802_15_4cmdRsp.into()); + ipcc.c1_set_tx_channel(channels::Cpu1Channel::Mac802_15_4cmdRsp.into(), true); + } + + pub(crate) fn send_ack(ipcc: &mut Ipcc) { + // TODO + unsafe { + let packet: &mut CmdPacket = &mut *(*TL_REF_TABLE.assume_init().mac_802_15_4_table).pnotack_buffer.cast(); + packet.cmd_serial.ty = TlPacketType::OtAck as u8; + } + + ipcc.c1_clear_flag_channel(channels::Cpu2Channel::Mac802_15_4NotifAck.into()); + ipcc.c1_set_rx_channel(channels::Cpu2Channel::Mac802_15_4NotifAck.into(), true); + } +} diff --git a/embassy-stm32/src/tl_mbox/mm.rs b/embassy-stm32/src/tl_mbox/mm.rs index f99ffa39..5dec397e 100644 --- a/embassy-stm32/src/tl_mbox/mm.rs +++ b/embassy-stm32/src/tl_mbox/mm.rs @@ -11,7 +11,7 @@ use crate::ipcc::Ipcc; pub struct MemoryManager; impl MemoryManager { - pub fn new() -> Self { + pub fn init() -> Self { unsafe { LinkedListNode::init_head(FREE_BUFF_QUEUE.as_mut_ptr()); LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()); @@ -31,9 +31,9 @@ impl MemoryManager { } pub fn evt_handler(ipcc: &mut Ipcc) { - ipcc.c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false); + ipcc.c1_set_tx_channel(channels::Cpu1Channel::MmReleaseBuffer.into(), false); Self::send_free_buf(); - ipcc.c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL); + ipcc.c1_set_flag_channel(channels::Cpu1Channel::MmReleaseBuffer.into()); } pub fn evt_drop(evt: *mut EvtPacket, ipcc: &mut Ipcc) { @@ -43,14 +43,14 @@ impl MemoryManager { 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); + let channel_is_busy = ipcc.c1_is_active_flag(channels::Cpu1Channel::MmReleaseBuffer.into()); // 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); + ipcc.c1_set_tx_channel(channels::Cpu1Channel::MmReleaseBuffer.into(), true); } else { Self::send_free_buf(); - ipcc.c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL); + ipcc.c1_set_flag_channel(channels::Cpu1Channel::MmReleaseBuffer.into()); } } diff --git a/embassy-stm32/src/tl_mbox/mod.rs b/embassy-stm32/src/tl_mbox/mod.rs index dc6104cc..b2d3a27e 100644 --- a/embassy-stm32/src/tl_mbox/mod.rs +++ b/embassy-stm32/src/tl_mbox/mod.rs @@ -4,9 +4,12 @@ use bit_field::BitField; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; +#[cfg(feature = "ble")] use self::ble::Ble; use self::cmd::{AclDataPacket, CmdPacket}; use self::evt::{CsEvt, EvtBox}; +#[cfg(feature = "mac-802_15_4")] +use self::mac_802_15_4::Mac802_15_4; use self::mm::MemoryManager; use self::shci::{shci_ble_init, ShciBleInitCmdParam}; use self::sys::Sys; @@ -14,7 +17,6 @@ use self::unsafe_linked_list::LinkedListNode; use crate::interrupt; use crate::ipcc::Ipcc; -mod ble; mod channels; mod cmd; mod consts; @@ -24,6 +26,11 @@ mod shci; mod sys; mod unsafe_linked_list; +#[cfg(feature = "ble")] +mod ble; +#[cfg(feature = "mac-802_15_4")] +mod mac_802_15_4; + pub type PacketHeader = LinkedListNode; const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::(); @@ -194,8 +201,8 @@ struct TracesTable { #[repr(C, packed)] struct Mac802_15_4Table { - pcmd_rsp_buffer: *const u8, - pnotack_buffer: *const u8, + pcmd_rsp_buffer: *mut u8, + pnotack_buffer: *mut u8, evt_queue: *const u8, } @@ -215,6 +222,7 @@ pub struct RefTable { ble_lld_table: *const BleLldTable, } +// -------------------- reference table -------------------- #[link_section = "TL_REF_TABLE"] pub static mut TL_REF_TABLE: MaybeUninit = MaybeUninit::uninit(); @@ -248,38 +256,50 @@ static mut TL_MAC_802_15_4_TABLE: MaybeUninit = MaybeUninit::u #[link_section = "MB_MEM1"] static mut TL_ZIGBEE_TABLE: MaybeUninit = MaybeUninit::uninit(); -#[allow(dead_code)] // Not used currently but reserved +// -------------------- tables -------------------- #[link_section = "MB_MEM1"] static mut FREE_BUFF_QUEUE: MaybeUninit = MaybeUninit::uninit(); -// not in shared RAM -static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit(); - #[link_section = "MB_MEM2"] static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> = MaybeUninit::uninit(); -#[link_section = "MB_MEM2"] +#[link_section = "MB_MEM1"] static mut EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); #[link_section = "MB_MEM2"] static mut SYSTEM_EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); -#[link_section = "MB_MEM2"] -static mut SYS_CMD_BUF: MaybeUninit = MaybeUninit::uninit(); +// not in shared RAM +static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit(); +// -------------------- app tables -------------------- #[link_section = "MB_MEM2"] static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit(); +#[link_section = "MB_MEM2"] +static mut SYS_CMD_BUF: MaybeUninit = MaybeUninit::uninit(); + #[link_section = "MB_MEM2"] static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = MaybeUninit::uninit(); +#[cfg(feature = "mac-802_15_4")] +#[link_section = "MB_MEM2"] +static mut MAC_802_15_4_CMD_BUFFER: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "mac-802_15_4")] +#[link_section = "MB_MEM2"] +static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = + MaybeUninit::uninit(); + +#[cfg(feature = "ble")] #[link_section = "MB_MEM2"] static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = MaybeUninit::uninit(); -#[link_section = "MB_MEM2"] +#[cfg(feature = "ble")] +#[link_section = "MB_MEM1"] static mut BLE_CMD_BUFFER: MaybeUninit = MaybeUninit::uninit(); #[link_section = "MB_MEM2"] @@ -289,10 +309,14 @@ static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251 // TODO: get a better size, this is a placeholder pub(crate) static TL_CHANNEL: Channel = Channel::new(); -pub struct TlMbox { - _sys: Sys, - _ble: Ble, - _mm: MemoryManager, +pub struct TlMbox; + +pub enum MailboxTarget { + Sys, + #[cfg(feature = "ble")] + Ble, + #[cfg(feature = "mac-802_15_4")] + Mac802_15_4, } impl TlMbox { @@ -338,9 +362,14 @@ impl TlMbox { ipcc.init(); - let _sys = Sys::new(ipcc); - let _ble = Ble::new(ipcc); - let _mm = MemoryManager::new(); + Sys::init(ipcc); + MemoryManager::init(); + + #[cfg(feature = "ble")] + Ble::init(ipcc); + + #[cfg(feature = "mac-802_15_4")] + Mac802_15_4::init(ipcc); // rx_irq.disable(); // tx_irq.disable(); @@ -360,7 +389,7 @@ impl TlMbox { // rx_irq.enable(); // tx_irq.enable(); - TlMbox { _sys, _ble, _mm } + Self } pub fn wireless_fw_info(&self) -> Option { @@ -374,17 +403,30 @@ impl TlMbox { } } + #[cfg(feature = "ble")] 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_cmd(&self, ipcc: &mut Ipcc, buf: &[u8], target: MailboxTarget) { + match target { + MailboxTarget::Sys => Sys::send_cmd(ipcc, buf), + #[cfg(feature = "ble")] + MailboxTarget::Ble => Ble::send_cmd(ipcc, buf), + #[cfg(feature = "mac-802_15_4")] + MailboxTarget::Mac802_15_4 => Mac802_15_4::send_cmd(ipcc, buf), + } } - // pub fn send_sys_cmd(&self, ipcc: &mut Ipcc, buf: &[u8]) { - // sys::Sys::send_cmd(ipcc, buf); - // } + pub fn send_ack(&self, ipcc: &mut Ipcc, target: MailboxTarget) { + match target { + #[cfg(feature = "ble")] + MailboxTarget::Ble => Ble::send_acl_data(ipcc), + #[cfg(feature = "mac-802_15_4")] + MailboxTarget::Mac802_15_4 => Mac802_15_4::send_ack(ipcc), + MailboxTarget::Sys => { /* does nothing */ } + } + } pub async fn read(&self) -> EvtBox { TL_CHANNEL.recv().await @@ -392,10 +434,14 @@ impl TlMbox { #[allow(dead_code)] 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); + if ipcc.is_rx_pending(channels::Cpu2Channel::SystemEvent.into()) { + Sys::evt_handler(ipcc); + } else if cfg!(feature = "ble") && ipcc.is_rx_pending(channels::Cpu2Channel::BleEvent.into()) { + Ble::evt_handler(ipcc); + } else if cfg!(feature = "mac-802_15_4") + && ipcc.is_rx_pending(channels::Cpu2Channel::Mac802_15_4NotifAck.into()) + { + Mac802_15_4::notif_evt_handler(ipcc); } else { todo!() } @@ -403,11 +449,16 @@ impl TlMbox { #[allow(dead_code)] fn interrupt_ipcc_tx_handler(ipcc: &mut Ipcc) { - if ipcc.is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) { + if ipcc.is_tx_pending(channels::Cpu1Channel::SystemCmdRsp.into()) { // 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); + let _ = Sys::cmd_evt_handler(ipcc); + } else if ipcc.is_tx_pending(channels::Cpu1Channel::MmReleaseBuffer.into()) { + MemoryManager::evt_handler(ipcc); + } else if cfg!(feature = "ble") && ipcc.is_tx_pending(channels::Cpu1Channel::HciAclData.into()) { + Ble::acl_data_evt_handler(ipcc); + } else if cfg!(feature = "mac-802_15_4") && ipcc.is_tx_pending(channels::Cpu1Channel::Mac802_15_4cmdRsp.into()) + { + Mac802_15_4::cmd_evt_handler(ipcc) } else { todo!() } diff --git a/embassy-stm32/src/tl_mbox/shci.rs b/embassy-stm32/src/tl_mbox/shci.rs index 61fd9e4a..53f0882b 100644 --- a/embassy-stm32/src/tl_mbox/shci.rs +++ b/embassy-stm32/src/tl_mbox/shci.rs @@ -95,7 +95,7 @@ pub fn shci_ble_init(ipcc: &mut Ipcc, param: ShciBleInitCmdParam) { 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); + ipcc.c1_set_flag_channel(channels::Cpu1Channel::SystemCmdRsp.into()); + ipcc.c1_set_tx_channel(channels::Cpu1Channel::SystemCmdRsp.into(), true); } } diff --git a/embassy-stm32/src/tl_mbox/sys.rs b/embassy-stm32/src/tl_mbox/sys.rs index 31ebde72..1dc43bfe 100644 --- a/embassy-stm32/src/tl_mbox/sys.rs +++ b/embassy-stm32/src/tl_mbox/sys.rs @@ -12,7 +12,7 @@ use crate::ipcc::Ipcc; pub struct Sys; impl Sys { - pub(crate) fn new(ipcc: &mut Ipcc) -> Self { + pub(crate) fn init(ipcc: &mut Ipcc) -> Self { unsafe { LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr()); @@ -22,7 +22,7 @@ impl Sys { }); } - ipcc.c1_set_rx_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, true); + ipcc.c1_set_rx_channel(channels::Cpu2Channel::SystemEvent.into(), true); Sys } @@ -43,11 +43,11 @@ impl Sys { } } - ipcc.c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL); + ipcc.c1_clear_flag_channel(channels::Cpu2Channel::SystemEvent.into()); } pub(crate) fn cmd_evt_handler(ipcc: &mut Ipcc) -> CcEvt { - ipcc.c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false); + ipcc.c1_set_tx_channel(channels::Cpu1Channel::SystemCmdRsp.into(), false); // ST's command response data structure is really convoluted. // @@ -67,12 +67,10 @@ impl Sys { } } - #[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: *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()); @@ -80,8 +78,8 @@ impl Sys { 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); + ipcc.c1_set_flag_channel(channels::Cpu1Channel::SystemCmdRsp.into()); + ipcc.c1_set_tx_channel(channels::Cpu1Channel::SystemCmdRsp.into(), true); } } } From 2ccf9f3abd6c8ccde0e56f97cbe65e5fb4bc32ce Mon Sep 17 00:00:00 2001 From: goueslati Date: Fri, 26 May 2023 09:56:55 +0100 Subject: [PATCH 02/15] stm32/ipcc: static methods for IPCC --- embassy-stm32/src/ipcc.rs | 66 +++++++---------- embassy-stm32/src/tl_mbox/ble.rs | 12 +-- embassy-stm32/src/tl_mbox/evt.rs | 5 +- embassy-stm32/src/tl_mbox/mm.rs | 14 ++-- embassy-stm32/src/tl_mbox/mod.rs | 90 ++++++++++------------- embassy-stm32/src/tl_mbox/shci.rs | 6 +- embassy-stm32/src/tl_mbox/sys.rs | 20 ++--- examples/stm32wb/src/bin/tl_mbox.rs | 8 +- examples/stm32wb/src/bin/tl_mbox_tx_rx.rs | 21 +++--- 9 files changed, 104 insertions(+), 138 deletions(-) diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 2b9caf8e..ea33b32c 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -1,5 +1,3 @@ -use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; - use crate::ipcc::sealed::Instance; use crate::peripherals::IPCC; use crate::rcc::sealed::RccPeripheral; @@ -29,22 +27,10 @@ pub(crate) mod sealed { } } -pub struct Ipcc<'d> { - _peri: PeripheralRef<'d, IPCC>, -} +pub(crate) struct Ipcc; -impl<'d> Ipcc<'d> { - pub fn new(peri: impl Peripheral

+ 'd, _config: Config) -> Self { - Self::new_inner(peri) - } - - pub(crate) fn new_inner(peri: impl Peripheral

+ 'd) -> Self { - into_ref!(peri); - - Self { _peri: peri } - } - - pub fn init(&mut self) { +impl Ipcc { + pub(crate) fn init(_config: Config) { IPCC::enable(); IPCC::reset(); IPCC::set_cpu2(true); @@ -61,56 +47,60 @@ impl<'d> Ipcc<'d> { } } - pub fn c1_set_rx_channel(&mut self, channel: IpccChannel, enabled: bool) { + pub(crate) fn c1_set_rx_channel(channel: IpccChannel, enabled: bool) { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, !enabled)) } } - pub fn c1_get_rx_channel(&self, channel: IpccChannel) -> bool { + pub(crate) fn c1_get_rx_channel(channel: IpccChannel) -> bool { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled unsafe { !regs.cpu(0).mr().read().chom(channel as usize) } } - pub fn c2_set_rx_channel(&mut self, channel: IpccChannel, enabled: bool) { + #[allow(dead_code)] + pub(crate) fn c2_set_rx_channel(channel: IpccChannel, enabled: bool) { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled unsafe { regs.cpu(1).mr().modify(|w| w.set_chom(channel as usize, !enabled)) } } - pub fn c2_get_rx_channel(&self, channel: IpccChannel) -> bool { + #[allow(dead_code)] + pub(crate) fn c2_get_rx_channel(channel: IpccChannel) -> bool { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled unsafe { !regs.cpu(1).mr().read().chom(channel as usize) } } - pub fn c1_set_tx_channel(&mut self, channel: IpccChannel, enabled: bool) { + pub(crate) fn c1_set_tx_channel(channel: IpccChannel, enabled: bool) { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) } } - pub fn c1_get_tx_channel(&self, channel: IpccChannel) -> bool { + pub(crate) fn c1_get_tx_channel(channel: IpccChannel) -> bool { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled unsafe { !regs.cpu(0).mr().read().chfm(channel as usize) } } - pub fn c2_set_tx_channel(&mut self, channel: IpccChannel, enabled: bool) { + #[allow(dead_code)] + pub(crate) fn c2_set_tx_channel(channel: IpccChannel, enabled: bool) { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled unsafe { regs.cpu(1).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) } } - pub fn c2_get_tx_channel(&self, channel: IpccChannel) -> bool { + #[allow(dead_code)] + pub(crate) fn c2_get_tx_channel(channel: IpccChannel) -> bool { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled @@ -118,53 +108,51 @@ impl<'d> Ipcc<'d> { } /// clears IPCC receive channel status for CPU1 - pub fn c1_clear_flag_channel(&mut self, channel: IpccChannel) { + pub(crate) fn c1_clear_flag_channel(channel: IpccChannel) { let regs = IPCC::regs(); unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)) } } + #[allow(dead_code)] /// clears IPCC receive channel status for CPU2 - pub fn c2_clear_flag_channel(&mut self, channel: IpccChannel) { + pub(crate) fn c2_clear_flag_channel(channel: IpccChannel) { let regs = IPCC::regs(); unsafe { regs.cpu(1).scr().write(|w| w.set_chc(channel as usize, true)) } } - pub fn c1_set_flag_channel(&mut self, channel: IpccChannel) { + pub(crate) fn c1_set_flag_channel(channel: IpccChannel) { let regs = IPCC::regs(); unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)) } } - pub fn c2_set_flag_channel(&mut self, channel: IpccChannel) { + #[allow(dead_code)] + pub(crate) fn c2_set_flag_channel(channel: IpccChannel) { let regs = IPCC::regs(); unsafe { regs.cpu(1).scr().write(|w| w.set_chs(channel as usize, true)) } } - pub fn c1_is_active_flag(&self, channel: IpccChannel) -> bool { + pub(crate) fn c1_is_active_flag(channel: IpccChannel) -> bool { let regs = IPCC::regs(); unsafe { regs.cpu(0).sr().read().chf(channel as usize) } } - pub fn c2_is_active_flag(&self, channel: IpccChannel) -> bool { + pub(crate) fn c2_is_active_flag(channel: IpccChannel) -> bool { let regs = IPCC::regs(); unsafe { regs.cpu(1).sr().read().chf(channel as usize) } } - pub fn is_tx_pending(&self, channel: IpccChannel) -> bool { - !self.c1_is_active_flag(channel) && self.c1_get_tx_channel(channel) + pub(crate) fn is_tx_pending(channel: IpccChannel) -> bool { + !Self::c1_is_active_flag(channel) && Self::c1_get_tx_channel(channel) } - 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 _ } + pub(crate) fn is_rx_pending(channel: IpccChannel) -> bool { + Self::c2_is_active_flag(channel) && Self::c1_get_rx_channel(channel) } } diff --git a/embassy-stm32/src/tl_mbox/ble.rs b/embassy-stm32/src/tl_mbox/ble.rs index d8bf14d4..5cc0bb20 100644 --- a/embassy-stm32/src/tl_mbox/ble.rs +++ b/embassy-stm32/src/tl_mbox/ble.rs @@ -16,7 +16,7 @@ use crate::tl_mbox::cmd::CmdPacket; pub struct Ble; impl Ble { - pub(crate) fn new(ipcc: &mut Ipcc) -> Self { + pub(crate) fn new() -> Self { unsafe { LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); @@ -28,12 +28,12 @@ impl Ble { }); } - ipcc.c1_set_rx_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, true); + Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, true); Ble } - pub(crate) fn evt_handler(ipcc: &mut Ipcc) { + pub(crate) fn evt_handler() { unsafe { let mut node_ptr = core::ptr::null_mut(); let node_ptr_ptr: *mut _ = &mut node_ptr; @@ -48,10 +48,10 @@ impl Ble { } } - ipcc.c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL); + Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL); } - pub(crate) fn send_cmd(ipcc: &mut Ipcc, buf: &[u8]) { + pub(crate) fn send_cmd(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; @@ -63,6 +63,6 @@ impl Ble { cmd_packet.cmd_serial.ty = TlPacketType::BleCmd as u8; } - ipcc.c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL); + Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL); } } diff --git a/embassy-stm32/src/tl_mbox/evt.rs b/embassy-stm32/src/tl_mbox/evt.rs index 770133f2..04feb3e6 100644 --- a/embassy-stm32/src/tl_mbox/evt.rs +++ b/embassy-stm32/src/tl_mbox/evt.rs @@ -131,9 +131,6 @@ impl EvtBox { 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); + mm::MemoryManager::evt_drop(self.ptr); } } diff --git a/embassy-stm32/src/tl_mbox/mm.rs b/embassy-stm32/src/tl_mbox/mm.rs index f99ffa39..6e0818cf 100644 --- a/embassy-stm32/src/tl_mbox/mm.rs +++ b/embassy-stm32/src/tl_mbox/mm.rs @@ -30,27 +30,27 @@ impl MemoryManager { MemoryManager } - pub fn evt_handler(ipcc: &mut Ipcc) { - ipcc.c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false); + pub fn evt_handler() { + Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false); Self::send_free_buf(); - ipcc.c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL); + Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL); } - pub fn evt_drop(evt: *mut EvtPacket, ipcc: &mut Ipcc) { + pub fn evt_drop(evt: *mut EvtPacket) { unsafe { let list_node = evt.cast(); LinkedListNode::remove_tail(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), list_node); } - let channel_is_busy = ipcc.c1_is_active_flag(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL); + 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); + 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); + Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL); } } diff --git a/embassy-stm32/src/tl_mbox/mod.rs b/embassy-stm32/src/tl_mbox/mod.rs index dc6104cc..1c927efa 100644 --- a/embassy-stm32/src/tl_mbox/mod.rs +++ b/embassy-stm32/src/tl_mbox/mod.rs @@ -1,6 +1,7 @@ use core::mem::MaybeUninit; use bit_field::BitField; +use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; @@ -12,7 +13,7 @@ use self::shci::{shci_ble_init, ShciBleInitCmdParam}; use self::sys::Sys; use self::unsafe_linked_list::LinkedListNode; use crate::interrupt; -use crate::ipcc::Ipcc; +use crate::ipcc::{Config, Ipcc}; mod ble; mod channels; @@ -58,13 +59,30 @@ pub struct FusInfoTable { pub struct ReceiveInterruptHandler {} impl interrupt::Handler for ReceiveInterruptHandler { - unsafe fn on_interrupt() {} + unsafe fn on_interrupt() { + if Ipcc::is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) { + sys::Sys::evt_handler(); + } else if Ipcc::is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) { + ble::Ble::evt_handler(); + } else { + todo!() + } + } } pub struct TransmitInterruptHandler {} impl interrupt::Handler for TransmitInterruptHandler { - unsafe fn on_interrupt() {} + unsafe fn on_interrupt() { + if Ipcc::is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) { + // TODO: handle this case + let _ = sys::Sys::cmd_evt_handler(); + } else if Ipcc::is_tx_pending(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL) { + mm::MemoryManager::evt_handler(); + } else { + todo!() + } + } } /// # Version @@ -298,9 +316,9 @@ pub struct TlMbox { impl TlMbox { /// initializes low-level transport between CPU1 and BLE stack on CPU2 pub fn init( - ipcc: &mut Ipcc, _irqs: impl interrupt::Binding + interrupt::Binding, + config: Config, ) -> TlMbox { unsafe { TL_REF_TABLE = MaybeUninit::new(RefTable { @@ -336,29 +354,18 @@ impl TlMbox { HCI_ACL_DATA_BUFFER = MaybeUninit::zeroed(); } - ipcc.init(); + Ipcc::init(config); - let _sys = Sys::new(ipcc); - let _ble = Ble::new(ipcc); + let _sys = Sys::new(); + let _ble = Ble::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(); + // enable interrupts + unsafe { crate::interrupt::IPCC_C1_RX::steal() }.unpend(); + unsafe { crate::interrupt::IPCC_C1_TX::steal() }.unpend(); + + unsafe { crate::interrupt::IPCC_C1_RX::steal() }.enable(); + unsafe { crate::interrupt::IPCC_C1_TX::steal() }.enable(); TlMbox { _sys, _ble, _mm } } @@ -374,42 +381,19 @@ impl TlMbox { } } - pub fn shci_ble_init(&self, ipcc: &mut Ipcc, param: ShciBleInitCmdParam) { - shci_ble_init(ipcc, param); + pub fn shci_ble_init(&self, param: ShciBleInitCmdParam) { + shci_ble_init(param); } - pub fn send_ble_cmd(&self, ipcc: &mut Ipcc, buf: &[u8]) { - ble::Ble::send_cmd(ipcc, buf); + pub fn send_ble_cmd(&self, buf: &[u8]) { + ble::Ble::send_cmd(buf); } - // pub fn send_sys_cmd(&self, ipcc: &mut Ipcc, buf: &[u8]) { - // sys::Sys::send_cmd(ipcc, buf); + // pub fn send_sys_cmd(&self, buf: &[u8]) { + // sys::Sys::send_cmd(buf); // } pub async fn read(&self) -> EvtBox { TL_CHANNEL.recv().await } - - #[allow(dead_code)] - 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!() - } - } - - #[allow(dead_code)] - 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!() - } - } } diff --git a/embassy-stm32/src/tl_mbox/shci.rs b/embassy-stm32/src/tl_mbox/shci.rs index 61fd9e4a..3d7e994a 100644 --- a/embassy-stm32/src/tl_mbox/shci.rs +++ b/embassy-stm32/src/tl_mbox/shci.rs @@ -76,7 +76,7 @@ pub struct ShciBleInitCmdPacket { param: ShciBleInitCmdParam, } -pub fn shci_ble_init(ipcc: &mut Ipcc, param: ShciBleInitCmdParam) { +pub fn shci_ble_init(param: ShciBleInitCmdParam) { let mut packet = ShciBleInitCmdPacket { header: ShciHeader::default(), param, @@ -95,7 +95,7 @@ pub fn shci_ble_init(ipcc: &mut Ipcc, param: ShciBleInitCmdParam) { 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); + 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); } } diff --git a/embassy-stm32/src/tl_mbox/sys.rs b/embassy-stm32/src/tl_mbox/sys.rs index 31ebde72..79e25714 100644 --- a/embassy-stm32/src/tl_mbox/sys.rs +++ b/embassy-stm32/src/tl_mbox/sys.rs @@ -12,7 +12,7 @@ use crate::ipcc::Ipcc; pub struct Sys; impl Sys { - pub(crate) fn new(ipcc: &mut Ipcc) -> Self { + pub(crate) fn new() -> Self { unsafe { LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr()); @@ -22,12 +22,12 @@ impl Sys { }); } - ipcc.c1_set_rx_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, true); + Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, true); Sys } - pub(crate) fn evt_handler(ipcc: &mut Ipcc) { + pub(crate) fn evt_handler() { unsafe { let mut node_ptr = core::ptr::null_mut(); let node_ptr_ptr: *mut _ = &mut node_ptr; @@ -43,11 +43,11 @@ impl Sys { } } - ipcc.c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL); + 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); + pub(crate) fn cmd_evt_handler() -> CcEvt { + Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false); // ST's command response data structure is really convoluted. // @@ -68,11 +68,11 @@ impl Sys { } #[allow(dead_code)] - pub(crate) fn send_cmd(ipcc: &mut Ipcc, buf: &[u8]) { + pub(crate) fn send_cmd(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: *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()); @@ -80,8 +80,8 @@ impl Sys { 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); + 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); } } } diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs index 326e4be8..18d93a27 100644 --- a/examples/stm32wb/src/bin/tl_mbox.rs +++ b/examples/stm32wb/src/bin/tl_mbox.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::ipcc::{Config, Ipcc}; +use embassy_stm32::ipcc::Config; use embassy_stm32::tl_mbox::TlMbox; use embassy_stm32::{bind_interrupts, tl_mbox}; use embassy_time::{Duration, Timer}; @@ -41,13 +41,11 @@ async fn main(_spawner: Spawner) { 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()); + let _p = embassy_stm32::init(Default::default()); info!("Hello World!"); let config = Config::default(); - let mut ipcc = Ipcc::new(p.IPCC, config); - - let mbox = TlMbox::init(&mut ipcc, Irqs); + let mbox = TlMbox::init(Irqs, config); loop { let wireless_fw_info = mbox.wireless_fw_info(); diff --git a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs b/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs index 7a69f26b..41c450a5 100644 --- a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs +++ b/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::ipcc::{Config, Ipcc}; +use embassy_stm32::ipcc::Config; use embassy_stm32::tl_mbox::TlMbox; use embassy_stm32::{bind_interrupts, tl_mbox}; use {defmt_rtt as _, panic_probe as _}; @@ -40,16 +40,11 @@ async fn main(_spawner: Spawner) { 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()); + let _p = embassy_stm32::init(Default::default()); info!("Hello World!"); let config = Config::default(); - let mut ipcc = Ipcc::new(p.IPCC, config); - - let mbox = TlMbox::init(&mut ipcc, Irqs); - - // initialize ble stack, does not return a response - mbox.shci_ble_init(&mut ipcc, Default::default()); + let mbox = TlMbox::init(Irqs, config); info!("waiting for coprocessor to boot"); let event_box = mbox.read().await; @@ -74,10 +69,11 @@ async fn main(_spawner: Spawner) { ); } - mbox.shci_ble_init(&mut ipcc, Default::default()); + // initialize ble stack, does not return a response + mbox.shci_ble_init(Default::default()); info!("resetting BLE"); - mbox.send_ble_cmd(&mut ipcc, &[0x01, 0x03, 0x0c, 0x00, 0x00]); + mbox.send_ble_cmd(&[0x01, 0x03, 0x0c, 0x00, 0x00]); let event_box = mbox.read().await; @@ -92,7 +88,10 @@ async fn main(_spawner: Spawner) { info!( "==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}", - kind, code, payload_len, payload + kind, + code, + payload_len, + payload[3..] ); loop {} From 984cd47b417a7bab986ff11b589b88fcae2940b9 Mon Sep 17 00:00:00 2001 From: goueslati Date: Fri, 26 May 2023 10:03:01 +0100 Subject: [PATCH 03/15] stm32/ipcc: update test --- tests/stm32/src/bin/ble.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/stm32/src/bin/ble.rs b/tests/stm32/src/bin/ble.rs index aedf9a38..db5cc611 100644 --- a/tests/stm32/src/bin/ble.rs +++ b/tests/stm32/src/bin/ble.rs @@ -7,24 +7,24 @@ #[path = "../example_common.rs"] mod example_common; use embassy_executor::Spawner; -use embassy_stm32::interrupt; -use embassy_stm32::ipcc::{Config, Ipcc}; +use embassy_stm32::ipcc::Config; use embassy_stm32::tl_mbox::TlMbox; +use embassy_stm32::{bind_interrupts, tl_mbox}; use embassy_time::{Duration, Timer}; use example_common::*; +bind_interrupts!(struct Irqs{ + IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; + IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(config()); + let _p = embassy_stm32::init(config()); 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); + let mbox = TlMbox::init(Irqs, config); loop { let wireless_fw_info = mbox.wireless_fw_info(); From 66304a102d628f2e61f9e38bb95eb11a2663335d Mon Sep 17 00:00:00 2001 From: goueslati Date: Fri, 26 May 2023 11:26:58 +0100 Subject: [PATCH 04/15] Revert "Merge branch 'tl_mbox' into ipcc" This reverts commit 859e539f85c7f4770050cc11f83fe1f6d040cd1d, reversing changes made to 984cd47b417a7bab986ff11b589b88fcae2940b9. --- embassy-stm32/Cargo.toml | 10 -- embassy-stm32/src/tl_mbox/ble.rs | 11 -- embassy-stm32/src/tl_mbox/channels.rs | 144 ++++++++-------------- embassy-stm32/src/tl_mbox/mac_802_15_4.rs | 82 ------------ embassy-stm32/src/tl_mbox/mm.rs | 2 +- embassy-stm32/src/tl_mbox/mod.rs | 92 ++++---------- embassy-stm32/src/tl_mbox/sys.rs | 1 + 7 files changed, 75 insertions(+), 267 deletions(-) delete mode 100644 embassy-stm32/src/tl_mbox/mac_802_15_4.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 653f328c..0d7e03bf 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -110,16 +110,6 @@ unstable-pac = [] # Implement embedded-hal-async traits if `nightly` is set as well. unstable-traits = ["embedded-hal-1", "dep:embedded-hal-nb"] -# stm32wb specific -# support for wireless stacks -ble = [] -thread = [] -lld-tests = [] -ble-lld = [] -mac-802_15_4 = [] -zigbee = [] -traces = [] - # Chip-selection features stm32c011d6 = [ "stm32-metapac/stm32c011d6" ] stm32c011f4 = [ "stm32-metapac/stm32c011f4" ] diff --git a/embassy-stm32/src/tl_mbox/ble.rs b/embassy-stm32/src/tl_mbox/ble.rs index 0699d186..5cc0bb20 100644 --- a/embassy-stm32/src/tl_mbox/ble.rs +++ b/embassy-stm32/src/tl_mbox/ble.rs @@ -65,15 +65,4 @@ impl Ble { Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL); } - - pub(crate) fn send_acl_data() { - unsafe { - (*(*TL_REF_TABLE.assume_init().ble_table).phci_acl_data_buffer) - .acl_data_serial - .ty = TlPacketType::AclData as u8; - } - - Ipcc::c1_set_flag_channel(channels::Cpu1Channel::HciAclData.into()); - Ipcc::c1_set_tx_channel(channels::Cpu1Channel::HciAclData.into(), true); - } } diff --git a/embassy-stm32/src/tl_mbox/channels.rs b/embassy-stm32/src/tl_mbox/channels.rs index 94e97230..aaa6ce17 100644 --- a/embassy-stm32/src/tl_mbox/channels.rs +++ b/embassy-stm32/src/tl_mbox/channels.rs @@ -49,104 +49,56 @@ //! | | //! -use crate::ipcc::IpccChannel; +pub mod cpu1 { + use crate::ipcc::IpccChannel; -pub enum Cpu1Channel { - BleCmd, - SystemCmdRsp, - #[cfg(feature = "thread")] - ThreadOtCmdRsp, - #[cfg(feature = "zigbee")] - ZigbeeCmdAppli, - MmReleaseBuffer, - #[cfg(feature = "mac-802_15_4")] - Mac802_15_4cmdRsp, - #[cfg(feature = "thread")] - ThreadCliCmd, - #[cfg(feature = "lld-tests")] - LldTestsCliCmd, - #[cfg(feature = "ble-lld")] - BleLldCmd, - HciAclData, + // Not used currently but reserved + pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1; + // Not used currently but reserved + pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; + // Not used currently but reserved + pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6; } -impl From for IpccChannel { - fn from(value: Cpu1Channel) -> Self { - match value { - Cpu1Channel::BleCmd => IpccChannel::Channel1, - Cpu1Channel::SystemCmdRsp => IpccChannel::Channel2, - #[cfg(feature = "thread")] - Cpu1Channel::ThreadOtCmdRsp => IpccChannel::Channel3, - #[cfg(feature = "zigbee")] - Cpu1Channel::ZigbeeCmdAppli => IpccChannel::Channel3, - #[cfg(feature = "mac-802_15_4")] - Cpu1Channel::Mac802_15_4cmdRsp => IpccChannel::Channel3, - Cpu1Channel::MmReleaseBuffer => IpccChannel::Channel4, - #[cfg(feature = "thread")] - Cpu1Channel::ThreadCliCmd => IpccChannel::Channel5, - #[cfg(feature = "lld-tests")] - Cpu1Channel::LldTestsCliCmd => IpccChannel::Channel5, - #[cfg(feature = "ble-lld")] - Cpu1Channel::BleLldCmd => IpccChannel::Channel5, - Cpu1Channel::HciAclData => IpccChannel::Channel6, - } - } -} +pub mod cpu2 { + use crate::ipcc::IpccChannel; -pub enum Cpu2Channel { - BleEvent, - SystemEvent, - #[cfg(feature = "thread")] - ThreadNotifAck, - #[cfg(feature = "zigbee")] - ZigbeeAppliNotifAck, - #[cfg(feature = "mac-802_15_4")] - Mac802_15_4NotifAck, - #[cfg(feature = "lld-tests")] - LldTestsM0Cmd, - #[cfg(feature = "ble-lld")] - BleLldM0Cmd, - #[cfg(feature = "traces")] - Traces, - #[cfg(feature = "thread")] - ThreadCliNotifAck, - #[cfg(feature = "lld-tests")] - LldTestsCliRsp, - #[cfg(feature = "ble-lld")] - BleLldCliRsp, - #[cfg(feature = "ble-lld")] - BleLldRsp, - #[cfg(feature = "zigbee")] - ZigbeeM0Request, -} - -impl From for IpccChannel { - fn from(value: Cpu2Channel) -> Self { - match value { - Cpu2Channel::BleEvent => IpccChannel::Channel1, - Cpu2Channel::SystemEvent => IpccChannel::Channel2, - #[cfg(feature = "thread")] - Cpu2Channel::ThreadNotifAck => IpccChannel::Channel3, - #[cfg(feature = "zigbee")] - Cpu2Channel::ZigbeeAppliNotifAck => IpccChannel::Channel3, - #[cfg(feature = "mac-802_15_4")] - Cpu2Channel::Mac802_15_4NotifAck => IpccChannel::Channel3, - #[cfg(feature = "lld-tests")] - Cpu2Channel::LldTestsM0Cmd => IpccChannel::Channel3, - #[cfg(feature = "ble-lld")] - Cpu2Channel::BleLldM0Cmd => IpccChannel::Channel3, - #[cfg(feature = "traces")] - Cpu2Channel::Traces => IpccChannel::Channel4, - #[cfg(feature = "thread")] - Cpu2Channel::ThreadCliNotifAck => IpccChannel::Channel5, - #[cfg(feature = "lld-tests")] - Cpu2Channel::LldTestsCliRsp => IpccChannel::Channel5, - #[cfg(feature = "ble-lld")] - Cpu2Channel::BleLldCliRsp => IpccChannel::Channel5, - #[cfg(feature = "ble-lld")] - Cpu2Channel::BleLldRsp => IpccChannel::Channel5, - #[cfg(feature = "zigbee")] - Cpu2Channel::ZigbeeM0Request => IpccChannel::Channel5, - } - } + pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1; + pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_BLE_LLD_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_BLE_LLD_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_BLE_LLD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5; + #[allow(dead_code)] // Not used currently but reserved + pub const IPCC_ZIGBEE_M0_REQUEST_CHANNEL: IpccChannel = IpccChannel::Channel5; } diff --git a/embassy-stm32/src/tl_mbox/mac_802_15_4.rs b/embassy-stm32/src/tl_mbox/mac_802_15_4.rs deleted file mode 100644 index 19f95113..00000000 --- a/embassy-stm32/src/tl_mbox/mac_802_15_4.rs +++ /dev/null @@ -1,82 +0,0 @@ -use core::mem::MaybeUninit; - -use embassy_futures::block_on; - -use super::cmd::{CmdPacket, CmdSerial}; -use super::consts::TlPacketType; -use super::evt::{EvtBox, EvtPacket}; -use super::unsafe_linked_list::LinkedListNode; -use super::{ - channels, Mac802_15_4Table, EVT_QUEUE, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, TL_CHANNEL, - TL_MAC_802_15_4_TABLE, TL_REF_TABLE, -}; -use crate::ipcc::Ipcc; - -pub struct Mac802_15_4; - -impl Mac802_15_4 { - pub(crate) fn init(ipcc: &mut Ipcc) -> Self { - unsafe { - LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); - - TL_MAC_802_15_4_TABLE = MaybeUninit::new(Mac802_15_4Table { - pcmd_rsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(), - pnotack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(), - evt_queue: EVT_QUEUE.as_ptr().cast(), - }); - } - - ipcc.c1_set_rx_channel(channels::Cpu2Channel::Mac802_15_4NotifAck.into(), true); - - Self - } - - pub(crate) fn notif_evt_handler(ipcc: &mut Ipcc) { - unsafe { - let notif_buffer: *mut EvtPacket = (*TL_REF_TABLE.assume_init().mac_802_15_4_table).pnotack_buffer.cast(); - let event = EvtBox::new(notif_buffer); - - block_on(TL_CHANNEL.send(event)); - } - - ipcc.c1_set_rx_channel(channels::Cpu2Channel::Mac802_15_4NotifAck.into(), false); - } - - pub(crate) fn cmd_evt_handler(ipcc: &mut Ipcc) { - unsafe { - let _notif_buffer = (*TL_REF_TABLE.assume_init().mac_802_15_4_table).pcmd_rsp_buffer; - - // NOTE: ST's HAL does nothing with this buffer, ?????? - } - - ipcc.c1_set_tx_channel(channels::Cpu1Channel::Mac802_15_4cmdRsp.into(), false); - } - - pub(crate) fn send_cmd(ipcc: &mut Ipcc, buf: &[u8]) { - unsafe { - let pcmd_buffer: *mut CmdPacket = (*TL_REF_TABLE.assume_init().mac_802_15_4_table).pcmd_rsp_buffer.cast(); - 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 CmdPacket = - &mut *(*TL_REF_TABLE.assume_init().mac_802_15_4_table).pcmd_rsp_buffer.cast(); - cmd_packet.cmd_serial.ty = TlPacketType::OtCmd as u8; - } - - ipcc.c1_set_flag_channel(channels::Cpu1Channel::Mac802_15_4cmdRsp.into()); - ipcc.c1_set_tx_channel(channels::Cpu1Channel::Mac802_15_4cmdRsp.into(), true); - } - - pub(crate) fn send_ack(ipcc: &mut Ipcc) { - // TODO - unsafe { - let packet: &mut CmdPacket = &mut *(*TL_REF_TABLE.assume_init().mac_802_15_4_table).pnotack_buffer.cast(); - packet.cmd_serial.ty = TlPacketType::OtAck as u8; - } - - ipcc.c1_clear_flag_channel(channels::Cpu2Channel::Mac802_15_4NotifAck.into()); - ipcc.c1_set_rx_channel(channels::Cpu2Channel::Mac802_15_4NotifAck.into(), true); - } -} diff --git a/embassy-stm32/src/tl_mbox/mm.rs b/embassy-stm32/src/tl_mbox/mm.rs index cb161ce5..6e0818cf 100644 --- a/embassy-stm32/src/tl_mbox/mm.rs +++ b/embassy-stm32/src/tl_mbox/mm.rs @@ -11,7 +11,7 @@ use crate::ipcc::Ipcc; pub struct MemoryManager; impl MemoryManager { - pub fn init() -> Self { + pub fn new() -> Self { unsafe { LinkedListNode::init_head(FREE_BUFF_QUEUE.as_mut_ptr()); LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()); diff --git a/embassy-stm32/src/tl_mbox/mod.rs b/embassy-stm32/src/tl_mbox/mod.rs index fe366f6d..1c927efa 100644 --- a/embassy-stm32/src/tl_mbox/mod.rs +++ b/embassy-stm32/src/tl_mbox/mod.rs @@ -5,12 +5,9 @@ use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; -#[cfg(feature = "ble")] use self::ble::Ble; use self::cmd::{AclDataPacket, CmdPacket}; use self::evt::{CsEvt, EvtBox}; -#[cfg(feature = "mac-802_15_4")] -use self::mac_802_15_4::Mac802_15_4; use self::mm::MemoryManager; use self::shci::{shci_ble_init, ShciBleInitCmdParam}; use self::sys::Sys; @@ -18,6 +15,7 @@ use self::unsafe_linked_list::LinkedListNode; use crate::interrupt; use crate::ipcc::{Config, Ipcc}; +mod ble; mod channels; mod cmd; mod consts; @@ -27,11 +25,6 @@ mod shci; mod sys; mod unsafe_linked_list; -#[cfg(feature = "ble")] -mod ble; -#[cfg(feature = "mac-802_15_4")] -mod mac_802_15_4; - pub type PacketHeader = LinkedListNode; const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::(); @@ -219,8 +212,8 @@ struct TracesTable { #[repr(C, packed)] struct Mac802_15_4Table { - pcmd_rsp_buffer: *mut u8, - pnotack_buffer: *mut u8, + pcmd_rsp_buffer: *const u8, + pnotack_buffer: *const u8, evt_queue: *const u8, } @@ -240,7 +233,6 @@ pub struct RefTable { ble_lld_table: *const BleLldTable, } -// -------------------- reference table -------------------- #[link_section = "TL_REF_TABLE"] pub static mut TL_REF_TABLE: MaybeUninit = MaybeUninit::uninit(); @@ -274,50 +266,38 @@ static mut TL_MAC_802_15_4_TABLE: MaybeUninit = MaybeUninit::u #[link_section = "MB_MEM1"] static mut TL_ZIGBEE_TABLE: MaybeUninit = MaybeUninit::uninit(); -// -------------------- tables -------------------- +#[allow(dead_code)] // Not used currently but reserved #[link_section = "MB_MEM1"] static mut FREE_BUFF_QUEUE: MaybeUninit = MaybeUninit::uninit(); +// not in shared RAM +static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit = 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 = MaybeUninit::uninit(); #[link_section = "MB_MEM2"] static mut SYSTEM_EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); -// not in shared RAM -static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit(); - -// -------------------- app tables -------------------- -#[link_section = "MB_MEM2"] -static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit(); - #[link_section = "MB_MEM2"] static mut SYS_CMD_BUF: MaybeUninit = MaybeUninit::uninit(); +#[link_section = "MB_MEM2"] +static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit(); + #[link_section = "MB_MEM2"] static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = MaybeUninit::uninit(); -#[cfg(feature = "mac-802_15_4")] -#[link_section = "MB_MEM2"] -static mut MAC_802_15_4_CMD_BUFFER: MaybeUninit = MaybeUninit::uninit(); - -#[cfg(feature = "mac-802_15_4")] -#[link_section = "MB_MEM2"] -static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = - MaybeUninit::uninit(); - -#[cfg(feature = "ble")] #[link_section = "MB_MEM2"] static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = MaybeUninit::uninit(); -#[cfg(feature = "ble")] -#[link_section = "MB_MEM1"] +#[link_section = "MB_MEM2"] static mut BLE_CMD_BUFFER: MaybeUninit = MaybeUninit::uninit(); #[link_section = "MB_MEM2"] @@ -327,14 +307,10 @@ static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251 // TODO: get a better size, this is a placeholder pub(crate) static TL_CHANNEL: Channel = Channel::new(); -pub struct TlMbox; - -pub enum MailboxTarget { - Sys, - #[cfg(feature = "ble")] - Ble, - #[cfg(feature = "mac-802_15_4")] - Mac802_15_4, +pub struct TlMbox { + _sys: Sys, + _ble: Ble, + _mm: MemoryManager, } impl TlMbox { @@ -380,14 +356,9 @@ impl TlMbox { Ipcc::init(config); - Sys::init(); - MemoryManager::init(); - - #[cfg(feature = "ble")] - Ble::init(); - - #[cfg(feature = "mac-802_15_4")] - Mac802_15_4::init(); + let _sys = Sys::new(); + let _ble = Ble::new(); + let _mm = MemoryManager::new(); // enable interrupts unsafe { crate::interrupt::IPCC_C1_RX::steal() }.unpend(); @@ -396,7 +367,7 @@ impl TlMbox { unsafe { crate::interrupt::IPCC_C1_RX::steal() }.enable(); unsafe { crate::interrupt::IPCC_C1_TX::steal() }.enable(); - Self + TlMbox { _sys, _ble, _mm } } pub fn wireless_fw_info(&self) -> Option { @@ -410,30 +381,17 @@ impl TlMbox { } } - #[cfg(feature = "ble")] pub fn shci_ble_init(&self, param: ShciBleInitCmdParam) { shci_ble_init(param); } - pub fn send_cmd(&self, buf: &[u8], target: MailboxTarget) { - match target { - MailboxTarget::Sys => Sys::send_cmd(buf), - #[cfg(feature = "ble")] - MailboxTarget::Ble => Ble::send_cmd(buf), - #[cfg(feature = "mac-802_15_4")] - MailboxTarget::Mac802_15_4 => Mac802_15_4::send_cmd(buf), - } + pub fn send_ble_cmd(&self, buf: &[u8]) { + ble::Ble::send_cmd(buf); } - pub fn send_ack(&self, target: MailboxTarget) { - match target { - #[cfg(feature = "ble")] - MailboxTarget::Ble => Ble::send_acl_data(), - #[cfg(feature = "mac-802_15_4")] - MailboxTarget::Mac802_15_4 => Mac802_15_4::send_ack(), - MailboxTarget::Sys => { /* does nothing */ } - } - } + // pub fn send_sys_cmd(&self, buf: &[u8]) { + // sys::Sys::send_cmd(buf); + // } pub async fn read(&self) -> EvtBox { TL_CHANNEL.recv().await diff --git a/embassy-stm32/src/tl_mbox/sys.rs b/embassy-stm32/src/tl_mbox/sys.rs index 4ffbe8e6..79e25714 100644 --- a/embassy-stm32/src/tl_mbox/sys.rs +++ b/embassy-stm32/src/tl_mbox/sys.rs @@ -70,6 +70,7 @@ impl Sys { #[allow(dead_code)] pub(crate) fn send_cmd(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(); From c19967dcf24d5223de5fd9b390371dc24aeccc1d Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 27 May 2023 15:03:25 -0500 Subject: [PATCH 05/15] stm32/ipcc: extract tl_mbox linker file to embassy-stm32 --- embassy-stm32/build.rs | 10 ++++++ .../tl_mbox.x.in | 14 ++------ examples/stm32wb/Cargo.toml | 2 +- examples/stm32wb/build.rs | 36 ++++--------------- examples/stm32wb/memory.x | 35 ------------------ 5 files changed, 20 insertions(+), 77 deletions(-) rename tests/stm32/memory_ble.x => embassy-stm32/tl_mbox.x.in (58%) delete mode 100644 examples/stm32wb/memory.x diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 54098172..9207cf3f 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -910,6 +910,16 @@ fn main() { println!("cargo:rustc-cfg={}x{}", &chip_name[..9], &chip_name[10..11]); } + // ======== + // stm32wb tl_mbox link sections + + if chip_name.starts_with("stm32wb") { + let out_file = out_dir.join("tl_mbox.x").to_string_lossy().to_string(); + fs::write(out_file, fs::read_to_string("tl_mbox.x.in").unwrap()).unwrap(); + println!("cargo:rustc-link-search={}", out_dir.display()); + println!("cargo:rerun-if-changed=tl_mbox.x.in"); + } + // ======= // Features for targeting groups of chips diff --git a/tests/stm32/memory_ble.x b/embassy-stm32/tl_mbox.x.in similarity index 58% rename from tests/stm32/memory_ble.x rename to embassy-stm32/tl_mbox.x.in index 4332e2c7..b6eecb42 100644 --- a/tests/stm32/memory_ble.x +++ b/embassy-stm32/tl_mbox.x.in @@ -1,21 +1,13 @@ -/* - Memory size for STM32WB55xG with 512K FLASH -*/ - -MEMORY +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 { +SECTIONS +{ TL_REF_TABLE (NOLOAD) : { *(TL_REF_TABLE) } >RAM_SHARED MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 3c7e3e87..8cfac772 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32wb/build.rs b/examples/stm32wb/build.rs index 30691aa9..29b3a9b2 100644 --- a/examples/stm32wb/build.rs +++ b/examples/stm32wb/build.rs @@ -1,35 +1,11 @@ -//! This build script copies the `memory.x` file from the crate root into -//! a directory where the linker can always find it at build time. -//! For many projects this is optional, as the linker always searches the -//! project root directory -- wherever `Cargo.toml` is. However, if you -//! are using a workspace or have a more complicated build setup, this -//! build script becomes required. Additionally, by requesting that -//! Cargo re-run the build script whenever `memory.x` is changed, -//! updating `memory.x` ensures a rebuild of the application with the -//! new memory settings. - -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; - -fn main() { - // Put `memory.x` in our output directory and ensure it's - // on the linker search path. - let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - File::create(out.join("memory.x")) - .unwrap() - .write_all(include_bytes!("memory.x")) - .unwrap(); - println!("cargo:rustc-link-search={}", out.display()); - - // By default, Cargo will re-run a build script whenever - // any file in the project changes. By specifying `memory.x` - // here, we ensure the build script is only re-run when - // `memory.x` is changed. - println!("cargo:rerun-if-changed=memory.x"); +use std::error::Error; +fn main() -> Result<(), Box> { println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rerun-if-changed=link.x"); + println!("cargo:rustc-link-arg-bins=-Ttl_mbox.x"); println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + + Ok(()) } diff --git a/examples/stm32wb/memory.x b/examples/stm32wb/memory.x deleted file mode 100644 index e1f0530b..00000000 --- a/examples/stm32wb/memory.x +++ /dev/null @@ -1,35 +0,0 @@ -/* - The size of this file must be exactly the same as in other memory_xx.x files. - Memory size for STM32WB55xC with 256K FLASH -*/ - -MEMORY -{ - FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K - RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K - RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K -} - -/* - 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 -} From 7e501855fc2ee98bef6be56244c4587610dbdc32 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 27 May 2023 15:05:07 -0500 Subject: [PATCH 06/15] stm32/ipcc: move into tl_mbox --- embassy-stm32/src/lib.rs | 2 -- embassy-stm32/src/{ => tl_mbox}/ipcc.rs | 40 ++++++++++++------------- 2 files changed, 20 insertions(+), 22 deletions(-) rename embassy-stm32/src/{ => tl_mbox}/ipcc.rs (75%) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index c9df5c1b..b9d7a15c 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -41,8 +41,6 @@ pub mod crc; pub mod flash; #[cfg(all(spi_v1, rcc_f4))] pub mod i2s; -#[cfg(stm32wb)] -pub mod ipcc; pub mod pwm; #[cfg(quadspi)] pub mod qspi; diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/tl_mbox/ipcc.rs similarity index 75% rename from embassy-stm32/src/ipcc.rs rename to embassy-stm32/src/tl_mbox/ipcc.rs index ea33b32c..d1ac731e 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/tl_mbox/ipcc.rs @@ -1,4 +1,4 @@ -use crate::ipcc::sealed::Instance; +use self::sealed::Instance; use crate::peripherals::IPCC; use crate::rcc::sealed::RccPeripheral; @@ -20,17 +20,17 @@ pub enum IpccChannel { Channel6 = 5, } -pub(crate) mod sealed { +pub mod sealed { pub trait Instance: crate::rcc::RccPeripheral { fn regs() -> crate::pac::ipcc::Ipcc; fn set_cpu2(enabled: bool); } } -pub(crate) struct Ipcc; +pub struct Ipcc; impl Ipcc { - pub(crate) fn init(_config: Config) { + pub fn enable(_config: Config) { IPCC::enable(); IPCC::reset(); IPCC::set_cpu2(true); @@ -47,14 +47,14 @@ impl Ipcc { } } - pub(crate) fn c1_set_rx_channel(channel: IpccChannel, enabled: bool) { + pub fn c1_set_rx_channel(channel: IpccChannel, enabled: bool) { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, !enabled)) } } - pub(crate) fn c1_get_rx_channel(channel: IpccChannel) -> bool { + pub fn c1_get_rx_channel(channel: IpccChannel) -> bool { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled @@ -62,7 +62,7 @@ impl Ipcc { } #[allow(dead_code)] - pub(crate) fn c2_set_rx_channel(channel: IpccChannel, enabled: bool) { + pub fn c2_set_rx_channel(channel: IpccChannel, enabled: bool) { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled @@ -70,21 +70,21 @@ impl Ipcc { } #[allow(dead_code)] - pub(crate) fn c2_get_rx_channel(channel: IpccChannel) -> bool { + pub fn c2_get_rx_channel(channel: IpccChannel) -> bool { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled unsafe { !regs.cpu(1).mr().read().chom(channel as usize) } } - pub(crate) fn c1_set_tx_channel(channel: IpccChannel, enabled: bool) { + pub fn c1_set_tx_channel(channel: IpccChannel, enabled: bool) { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) } } - pub(crate) fn c1_get_tx_channel(channel: IpccChannel) -> bool { + pub fn c1_get_tx_channel(channel: IpccChannel) -> bool { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled @@ -92,7 +92,7 @@ impl Ipcc { } #[allow(dead_code)] - pub(crate) fn c2_set_tx_channel(channel: IpccChannel, enabled: bool) { + pub fn c2_set_tx_channel(channel: IpccChannel, enabled: bool) { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled @@ -100,7 +100,7 @@ impl Ipcc { } #[allow(dead_code)] - pub(crate) fn c2_get_tx_channel(channel: IpccChannel) -> bool { + pub fn c2_get_tx_channel(channel: IpccChannel) -> bool { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled @@ -108,7 +108,7 @@ impl Ipcc { } /// clears IPCC receive channel status for CPU1 - pub(crate) fn c1_clear_flag_channel(channel: IpccChannel) { + pub fn c1_clear_flag_channel(channel: IpccChannel) { let regs = IPCC::regs(); unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)) } @@ -116,42 +116,42 @@ impl Ipcc { #[allow(dead_code)] /// clears IPCC receive channel status for CPU2 - pub(crate) fn c2_clear_flag_channel(channel: IpccChannel) { + pub fn c2_clear_flag_channel(channel: IpccChannel) { let regs = IPCC::regs(); unsafe { regs.cpu(1).scr().write(|w| w.set_chc(channel as usize, true)) } } - pub(crate) fn c1_set_flag_channel(channel: IpccChannel) { + pub fn c1_set_flag_channel(channel: IpccChannel) { let regs = IPCC::regs(); unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)) } } #[allow(dead_code)] - pub(crate) fn c2_set_flag_channel(channel: IpccChannel) { + pub fn c2_set_flag_channel(channel: IpccChannel) { let regs = IPCC::regs(); unsafe { regs.cpu(1).scr().write(|w| w.set_chs(channel as usize, true)) } } - pub(crate) fn c1_is_active_flag(channel: IpccChannel) -> bool { + pub fn c1_is_active_flag(channel: IpccChannel) -> bool { let regs = IPCC::regs(); unsafe { regs.cpu(0).sr().read().chf(channel as usize) } } - pub(crate) fn c2_is_active_flag(channel: IpccChannel) -> bool { + pub fn c2_is_active_flag(channel: IpccChannel) -> bool { let regs = IPCC::regs(); unsafe { regs.cpu(1).sr().read().chf(channel as usize) } } - pub(crate) fn is_tx_pending(channel: IpccChannel) -> bool { + pub fn is_tx_pending(channel: IpccChannel) -> bool { !Self::c1_is_active_flag(channel) && Self::c1_get_tx_channel(channel) } - pub(crate) fn is_rx_pending(channel: IpccChannel) -> bool { + pub fn is_rx_pending(channel: IpccChannel) -> bool { Self::c2_is_active_flag(channel) && Self::c1_get_rx_channel(channel) } } From 37e104a6b380c3c7ec20346a44b11050476a6116 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 27 May 2023 15:05:23 -0500 Subject: [PATCH 07/15] stm32/ipcc: refactor tl_mbox --- embassy-stm32/src/tl_mbox/ble.rs | 14 +++----- embassy-stm32/src/tl_mbox/channels.rs | 4 +-- embassy-stm32/src/tl_mbox/evt.rs | 4 +-- embassy-stm32/src/tl_mbox/mm.rs | 10 ++---- embassy-stm32/src/tl_mbox/mod.rs | 46 +++++++++++++++++++-------- embassy-stm32/src/tl_mbox/shci.rs | 2 +- embassy-stm32/src/tl_mbox/sys.rs | 16 ++++------ 7 files changed, 51 insertions(+), 45 deletions(-) diff --git a/embassy-stm32/src/tl_mbox/ble.rs b/embassy-stm32/src/tl_mbox/ble.rs index 5cc0bb20..06237799 100644 --- a/embassy-stm32/src/tl_mbox/ble.rs +++ b/embassy-stm32/src/tl_mbox/ble.rs @@ -1,5 +1,3 @@ -use core::mem::MaybeUninit; - use embassy_futures::block_on; use super::cmd::CmdSerial; @@ -10,17 +8,17 @@ 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; +use crate::tl_mbox::ipcc::Ipcc; pub struct Ble; impl Ble { - pub(crate) fn new() -> Self { + pub fn enable() { unsafe { LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); - TL_BLE_TABLE = MaybeUninit::new(BleTable { + TL_BLE_TABLE.as_mut_ptr().write_volatile(BleTable { pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(), pcs_buffer: CS_BUFFER.as_mut_ptr().cast(), pevt_queue: EVT_QUEUE.as_ptr().cast(), @@ -29,11 +27,9 @@ impl Ble { } Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, true); - - Ble } - pub(crate) fn evt_handler() { + pub fn evt_handler() { unsafe { let mut node_ptr = core::ptr::null_mut(); let node_ptr_ptr: *mut _ = &mut node_ptr; @@ -51,7 +47,7 @@ impl Ble { Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL); } - pub(crate) fn send_cmd(buf: &[u8]) { + pub fn send_cmd(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; diff --git a/embassy-stm32/src/tl_mbox/channels.rs b/embassy-stm32/src/tl_mbox/channels.rs index aaa6ce17..25a065ba 100644 --- a/embassy-stm32/src/tl_mbox/channels.rs +++ b/embassy-stm32/src/tl_mbox/channels.rs @@ -50,7 +50,7 @@ //! pub mod cpu1 { - use crate::ipcc::IpccChannel; + use crate::tl_mbox::ipcc::IpccChannel; // Not used currently but reserved pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1; @@ -75,7 +75,7 @@ pub mod cpu1 { } pub mod cpu2 { - use crate::ipcc::IpccChannel; + use crate::tl_mbox::ipcc::IpccChannel; pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1; pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2; diff --git a/embassy-stm32/src/tl_mbox/evt.rs b/embassy-stm32/src/tl_mbox/evt.rs index 04feb3e6..47a8b72f 100644 --- a/embassy-stm32/src/tl_mbox/evt.rs +++ b/embassy-stm32/src/tl_mbox/evt.rs @@ -3,7 +3,7 @@ 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; +use crate::tl_mbox::mm::MemoryManager; /// the payload of [`Evt`] for a command status event #[derive(Copy, Clone)] @@ -131,6 +131,6 @@ impl EvtBox { impl Drop for EvtBox { fn drop(&mut self) { - mm::MemoryManager::evt_drop(self.ptr); + MemoryManager::evt_drop(self.ptr); } } diff --git a/embassy-stm32/src/tl_mbox/mm.rs b/embassy-stm32/src/tl_mbox/mm.rs index 6e0818cf..e28a6aa0 100644 --- a/embassy-stm32/src/tl_mbox/mm.rs +++ b/embassy-stm32/src/tl_mbox/mm.rs @@ -1,22 +1,20 @@ -use core::mem::MaybeUninit; - use super::evt::EvtPacket; use super::unsafe_linked_list::LinkedListNode; use super::{ channels, MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE, TL_REF_TABLE, }; -use crate::ipcc::Ipcc; +use crate::tl_mbox::ipcc::Ipcc; pub struct MemoryManager; impl MemoryManager { - pub fn new() -> Self { + pub fn enable() { unsafe { LinkedListNode::init_head(FREE_BUFF_QUEUE.as_mut_ptr()); LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()); - TL_MEM_MANAGER_TABLE = MaybeUninit::new(MemManagerTable { + TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable { spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(), spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(), ble_pool: EVT_POOL.as_ptr().cast(), @@ -26,8 +24,6 @@ impl MemoryManager { traces_pool_size: 0, }); } - - MemoryManager } pub fn evt_handler() { diff --git a/embassy-stm32/src/tl_mbox/mod.rs b/embassy-stm32/src/tl_mbox/mod.rs index 1c927efa..616f7dc5 100644 --- a/embassy-stm32/src/tl_mbox/mod.rs +++ b/embassy-stm32/src/tl_mbox/mod.rs @@ -1,7 +1,9 @@ use core::mem::MaybeUninit; +use atomic_polyfill::{compiler_fence, Ordering}; use bit_field::BitField; use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; +use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; @@ -13,13 +15,16 @@ use self::shci::{shci_ble_init, ShciBleInitCmdParam}; use self::sys::Sys; use self::unsafe_linked_list::LinkedListNode; use crate::interrupt; -use crate::ipcc::{Config, Ipcc}; +use crate::peripherals::IPCC; +pub use crate::tl_mbox::ipcc::Config; +use crate::tl_mbox::ipcc::Ipcc; mod ble; mod channels; mod cmd; mod consts; mod evt; +mod ipcc; mod mm; mod shci; mod sys; @@ -60,6 +65,8 @@ pub struct ReceiveInterruptHandler {} impl interrupt::Handler for ReceiveInterruptHandler { unsafe fn on_interrupt() { + // info!("ipcc rx interrupt"); + if Ipcc::is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) { sys::Sys::evt_handler(); } else if Ipcc::is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) { @@ -74,6 +81,8 @@ pub struct TransmitInterruptHandler {} impl interrupt::Handler for TransmitInterruptHandler { unsafe fn on_interrupt() { + // info!("ipcc tx interrupt"); + if Ipcc::is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) { // TODO: handle this case let _ = sys::Sys::cmd_evt_handler(); @@ -307,21 +316,24 @@ static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251 // TODO: get a better size, this is a placeholder pub(crate) static TL_CHANNEL: Channel = Channel::new(); -pub struct TlMbox { - _sys: Sys, - _ble: Ble, - _mm: MemoryManager, +pub struct TlMbox<'d> { + _ipcc: PeripheralRef<'d, IPCC>, } -impl TlMbox { +impl<'d> TlMbox<'d> { /// initializes low-level transport between CPU1 and BLE stack on CPU2 - pub fn init( + pub fn new( + ipcc: impl Peripheral

+ 'd, _irqs: impl interrupt::Binding + interrupt::Binding, config: Config, - ) -> TlMbox { + ) -> Self { + into_ref!(ipcc); + unsafe { - TL_REF_TABLE = MaybeUninit::new(RefTable { + compiler_fence(Ordering::AcqRel); + + TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable { device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(), ble_table: TL_BLE_TABLE.as_ptr(), thread_table: TL_THREAD_TABLE.as_ptr(), @@ -334,6 +346,10 @@ impl TlMbox { ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(), }); + // info!("TL_REF_TABLE addr: {:x}", TL_REF_TABLE.as_ptr() as usize); + + compiler_fence(Ordering::AcqRel); + TL_SYS_TABLE = MaybeUninit::zeroed(); TL_DEVICE_INFO_TABLE = MaybeUninit::zeroed(); TL_BLE_TABLE = MaybeUninit::zeroed(); @@ -352,13 +368,15 @@ impl TlMbox { CS_BUFFER = MaybeUninit::zeroed(); BLE_CMD_BUFFER = MaybeUninit::zeroed(); HCI_ACL_DATA_BUFFER = MaybeUninit::zeroed(); + + compiler_fence(Ordering::AcqRel); } - Ipcc::init(config); + Ipcc::enable(config); - let _sys = Sys::new(); - let _ble = Ble::new(); - let _mm = MemoryManager::new(); + Sys::enable(); + Ble::enable(); + MemoryManager::enable(); // enable interrupts unsafe { crate::interrupt::IPCC_C1_RX::steal() }.unpend(); @@ -367,7 +385,7 @@ impl TlMbox { unsafe { crate::interrupt::IPCC_C1_RX::steal() }.enable(); unsafe { crate::interrupt::IPCC_C1_TX::steal() }.enable(); - TlMbox { _sys, _ble, _mm } + Self { _ipcc: ipcc } } pub fn wireless_fw_info(&self) -> Option { diff --git a/embassy-stm32/src/tl_mbox/shci.rs b/embassy-stm32/src/tl_mbox/shci.rs index 3d7e994a..6b5b2dd1 100644 --- a/embassy-stm32/src/tl_mbox/shci.rs +++ b/embassy-stm32/src/tl_mbox/shci.rs @@ -3,7 +3,7 @@ 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; +use crate::tl_mbox::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; diff --git a/embassy-stm32/src/tl_mbox/sys.rs b/embassy-stm32/src/tl_mbox/sys.rs index 79e25714..9685fb92 100644 --- a/embassy-stm32/src/tl_mbox/sys.rs +++ b/embassy-stm32/src/tl_mbox/sys.rs @@ -1,5 +1,3 @@ -use core::mem::MaybeUninit; - use embassy_futures::block_on; use super::cmd::{CmdPacket, CmdSerial}; @@ -7,27 +5,25 @@ 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::tl_mbox::ipcc::Ipcc; pub struct Sys; impl Sys { - pub(crate) fn new() -> Self { + pub fn enable() { unsafe { LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr()); - TL_SYS_TABLE = MaybeUninit::new(SysTable { + TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable { pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(), sys_queue: SYSTEM_EVT_QUEUE.as_ptr(), }); } Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, true); - - Sys } - pub(crate) fn evt_handler() { + pub fn evt_handler() { unsafe { let mut node_ptr = core::ptr::null_mut(); let node_ptr_ptr: *mut _ = &mut node_ptr; @@ -46,7 +42,7 @@ impl Sys { Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL); } - pub(crate) fn cmd_evt_handler() -> CcEvt { + pub fn cmd_evt_handler() -> CcEvt { Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false); // ST's command response data structure is really convoluted. @@ -68,7 +64,7 @@ impl Sys { } #[allow(dead_code)] - pub(crate) fn send_cmd(buf: &[u8]) { + pub fn send_cmd(buf: &[u8]) { unsafe { // TODO: check this let cmd_buffer = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer; From 09d52638b551a37c8b032ffb6daaa1abd2efa231 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 27 May 2023 15:05:50 -0500 Subject: [PATCH 08/15] stm32/ipcc: refactor examples and tests --- examples/stm32wb/src/bin/tl_mbox.rs | 14 ++++++++------ examples/stm32wb/src/bin/tl_mbox_tx_rx.rs | 10 +++++----- tests/stm32/.cargo/config.toml | 6 ++++-- tests/stm32/Cargo.toml | 6 +++--- tests/stm32/build.rs | 13 +++++++++---- tests/stm32/src/bin/{ble.rs => tl_mbox.rs} | 7 +++---- 6 files changed, 32 insertions(+), 24 deletions(-) rename tests/stm32/src/bin/{ble.rs => tl_mbox.rs} (89%) diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs index 18d93a27..8f4e70af 100644 --- a/examples/stm32wb/src/bin/tl_mbox.rs +++ b/examples/stm32wb/src/bin/tl_mbox.rs @@ -4,8 +4,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::ipcc::Config; -use embassy_stm32::tl_mbox::TlMbox; +use embassy_stm32::tl_mbox::{Config, TlMbox}; use embassy_stm32::{bind_interrupts, tl_mbox}; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -41,16 +40,16 @@ async fn main(_spawner: Spawner) { 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()); + let p = embassy_stm32::init(Default::default()); info!("Hello World!"); let config = Config::default(); - let mbox = TlMbox::init(Irqs, config); + let mbox = TlMbox::new(p.IPCC, Irqs, config); loop { let wireless_fw_info = mbox.wireless_fw_info(); match wireless_fw_info { - None => error!("not yet initialized"), + None => info!("not yet initialized"), Some(fw_info) => { let version_major = fw_info.version_major(); let version_minor = fw_info.version_minor(); @@ -68,6 +67,9 @@ async fn main(_spawner: Spawner) { } } - Timer::after(Duration::from_millis(500)).await; + Timer::after(Duration::from_millis(50)).await; } + + info!("Test OK"); + cortex_m::asm::bkpt(); } diff --git a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs b/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs index 41c450a5..1724d946 100644 --- a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs +++ b/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs @@ -4,8 +4,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::ipcc::Config; -use embassy_stm32::tl_mbox::TlMbox; +use embassy_stm32::tl_mbox::{Config, TlMbox}; use embassy_stm32::{bind_interrupts, tl_mbox}; use {defmt_rtt as _, panic_probe as _}; @@ -40,11 +39,11 @@ async fn main(_spawner: Spawner) { 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()); + let p = embassy_stm32::init(Default::default()); info!("Hello World!"); let config = Config::default(); - let mbox = TlMbox::init(Irqs, config); + let mbox = TlMbox::new(p.IPCC, Irqs, config); info!("waiting for coprocessor to boot"); let event_box = mbox.read().await; @@ -94,5 +93,6 @@ async fn main(_spawner: Spawner) { payload[3..] ); - loop {} + info!("Test OK"); + cortex_m::asm::bkpt(); } diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml index 29c4799a..48588f0b 100644 --- a/tests/stm32/.cargo/config.toml +++ b/tests/stm32/.cargo/config.toml @@ -3,8 +3,10 @@ build-std = ["core"] build-std-features = ["panic_immediate_abort"] [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "teleprobe client run --target bluepill-stm32f103c8 --elf" +#runner = "teleprobe client run --target bluepill-stm32f103c8 --elf" #runner = "teleprobe local run --chip STM32F103C8 --elf" +#runner = "teleprobe local run --chip STM32WB55RG --elf" +runner = "probe-run --chip STM32WB55RG" rustflags = [ # Code-size optimizations. @@ -14,7 +16,7 @@ rustflags = [ ] [build] -target = "thumbv7m-none-eabi" +target = "thumbv7em-none-eabi" [env] DEFMT_LOG = "trace" diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index bd8d90ab..23b5f9ca 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -12,7 +12,7 @@ stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma"] # Nucleo stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo -stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma"] # Nucleo +stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble"] # Nucleo stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board @@ -45,8 +45,8 @@ chrono = { version = "^0.4", default-features = false, optional = true} # BEGIN TESTS # Generated by gen_test.py. DO NOT EDIT. [[bin]] -name = "ble" -path = "src/bin/ble.rs" +name = "tl_mbox" +path = "src/bin/tl_mbox.rs" required-features = [ "ble",] [[bin]] diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs index ca76b70b..b4583147 100644 --- a/tests/stm32/build.rs +++ b/tests/stm32/build.rs @@ -9,17 +9,22 @@ fn main() -> Result<(), Box> { println!("cargo:rustc-link-arg-bins=--nmagic"); // too little RAM to run from RAM. - if cfg!(any(feature = "stm32f103c8", feature = "stm32c031c6")) { + if cfg!(any( + feature = "stm32f103c8", + feature = "stm32c031c6", + feature = "stm32wb55rg" + )) { println!("cargo:rustc-link-arg-bins=-Tlink.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 { println!("cargo:rustc-link-arg-bins=-Tlink_ram.x"); println!("cargo:rerun-if-changed=link_ram.x"); } + if cfg!(feature = "stm32wb55rg") { + println!("cargo:rustc-link-arg-bins=-Ttl_mbox.x"); + } + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); Ok(()) diff --git a/tests/stm32/src/bin/ble.rs b/tests/stm32/src/bin/tl_mbox.rs similarity index 89% rename from tests/stm32/src/bin/ble.rs rename to tests/stm32/src/bin/tl_mbox.rs index db5cc611..626e7ac6 100644 --- a/tests/stm32/src/bin/ble.rs +++ b/tests/stm32/src/bin/tl_mbox.rs @@ -7,8 +7,7 @@ #[path = "../example_common.rs"] mod example_common; use embassy_executor::Spawner; -use embassy_stm32::ipcc::Config; -use embassy_stm32::tl_mbox::TlMbox; +use embassy_stm32::tl_mbox::{Config, TlMbox}; use embassy_stm32::{bind_interrupts, tl_mbox}; use embassy_time::{Duration, Timer}; use example_common::*; @@ -20,11 +19,11 @@ bind_interrupts!(struct Irqs{ #[embassy_executor::main] async fn main(_spawner: Spawner) { - let _p = embassy_stm32::init(config()); + let p = embassy_stm32::init(config()); info!("Hello World!"); let config = Config::default(); - let mbox = TlMbox::init(Irqs, config); + let mbox = TlMbox::new(p.IPCC, Irqs, config); loop { let wireless_fw_info = mbox.wireless_fw_info(); From 5d7301e510a0882d004cdaee337280816d490afd Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 27 May 2023 15:08:30 -0500 Subject: [PATCH 09/15] tests/stm32: revert cfg changes --- tests/stm32/.cargo/config.toml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml index 48588f0b..426d6e67 100644 --- a/tests/stm32/.cargo/config.toml +++ b/tests/stm32/.cargo/config.toml @@ -3,10 +3,8 @@ build-std = ["core"] build-std-features = ["panic_immediate_abort"] [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -#runner = "teleprobe client run --target bluepill-stm32f103c8 --elf" +runner = "teleprobe client run --target bluepill-stm32f103c8 --elf" #runner = "teleprobe local run --chip STM32F103C8 --elf" -#runner = "teleprobe local run --chip STM32WB55RG --elf" -runner = "probe-run --chip STM32WB55RG" rustflags = [ # Code-size optimizations. @@ -16,7 +14,7 @@ rustflags = [ ] [build] -target = "thumbv7em-none-eabi" +target = "thumbv7m-none-eabi" [env] -DEFMT_LOG = "trace" +DEFMT_LOG = "trace" \ No newline at end of file From bd6a1d38d208f770d15a70a89112fc74046a96ef Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 29 May 2023 09:16:50 -0500 Subject: [PATCH 10/15] stm32/tests: disable sdmmc test for now --- tests/stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index bd8d90ab..6e7a4a57 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -7,7 +7,7 @@ autobins = false [features] stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill -stm32f429zi = ["embassy-stm32/stm32f429zi", "sdmmc", "chrono", "not-gpdma"] # Nucleo +stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "not-gpdma"] # Nucleo "sdmmc" stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma"] # Nucleo stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo From 7b2a39a6fb62e0a1483b31e2d24dec71013558e7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 26 May 2023 23:05:18 +0200 Subject: [PATCH 11/15] Switch to Bender for CI. --- .github/ci/rust.sh | 21 ++++++++++ .github/workflows/rust.yml | 80 -------------------------------------- ci.sh | 1 - 3 files changed, 21 insertions(+), 81 deletions(-) create mode 100755 .github/ci/rust.sh delete mode 100644 .github/workflows/rust.yml diff --git a/.github/ci/rust.sh b/.github/ci/rust.sh new file mode 100755 index 00000000..af7f336c --- /dev/null +++ b/.github/ci/rust.sh @@ -0,0 +1,21 @@ +#!/bin/bash +## on push branch=main +## on push branch~=gh-readonly-queue/main/.* +## on pull_request + +set -euo pipefail + +echo Hello World! + +export RUSTUP_HOME=/ci/cache/rustup +export CARGO_HOME=/ci/cache/cargo +export CARGO_TARGET_DIR=/ci/cache/target +if [ -f /ci/secrets/teleprobe-token.txt ]; then + echo Got teleprobe token! + export TELEPROBE_TOKEN=$(cat /ci/secrets/teleprobe-token.txt) +fi + +hashtime restore /ci/cache/filetime.json || true +hashtime save /ci/cache/filetime.json + +./ci.sh diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml deleted file mode 100644 index 0cbca31b..00000000 --- a/.github/workflows/rust.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: Rust - -on: - push: - branches: [staging, trying, master] - pull_request: - branches: [master] - -env: - CARGO_TERM_COLOR: always - -jobs: - all: - runs-on: ubuntu-latest - needs: [build-nightly, build-stable, test] - steps: - - name: Done - run: exit 0 - build-nightly: - runs-on: ubuntu-latest - permissions: - id-token: write - contents: read - steps: - - uses: actions/checkout@v3 - with: - submodules: true - - name: Cache multiple paths - uses: actions/cache@v3 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - target_ci - key: rust3-${{ runner.os }}-${{ hashFiles('rust-toolchain.toml') }} - - name: build - env: - TELEPROBE_TOKEN: ${{ secrets.TELEPROBE_TOKEN }} - run: | - curl -L -o /usr/local/bin/cargo-batch https://github.com/embassy-rs/cargo-batch/releases/download/batch-0.3.0/cargo-batch - chmod +x /usr/local/bin/cargo-batch - ./ci.sh - rm -rf target_ci/*{,/release}/{build,deps,.fingerprint}/{lib,}{embassy,stm32}* - build-stable: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - submodules: true - - name: Cache multiple paths - uses: actions/cache@v3 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - target_ci_stable - key: rust-stable-${{ runner.os }}-${{ hashFiles('rust-toolchain.toml') }} - - name: build - run: | - curl -L -o /usr/local/bin/cargo-batch https://github.com/embassy-rs/cargo-batch/releases/download/batch-0.3.0/cargo-batch - chmod +x /usr/local/bin/cargo-batch - ./ci_stable.sh - rm -rf target_ci_stable/*{,/release}/{build,deps,.fingerprint}/{lib,}{embassy,stm32}* - - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Test boot - working-directory: ./embassy-boot/boot - run: cargo test && cargo test --features nightly && cargo test --features "ed25519-dalek,nightly" && cargo test --features "ed25519-salty,nightly" - - - name: Test sync - working-directory: ./embassy-sync - run: cargo test diff --git a/ci.sh b/ci.sh index 6d906f5f..11c56932 100755 --- a/ci.sh +++ b/ci.sh @@ -2,7 +2,6 @@ set -euo pipefail -export CARGO_TARGET_DIR=$PWD/target_ci export RUSTFLAGS=-Dwarnings export DEFMT_LOG=trace From 6cb6e575920613c2aefca22c06764a098521cf5b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 29 May 2023 18:49:50 +0200 Subject: [PATCH 12/15] CI fixes. --- .github/ci/rust.sh | 1 - .github/workflows/doc.yml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/ci/rust.sh b/.github/ci/rust.sh index af7f336c..db1fc853 100755 --- a/.github/ci/rust.sh +++ b/.github/ci/rust.sh @@ -1,5 +1,4 @@ #!/bin/bash -## on push branch=main ## on push branch~=gh-readonly-queue/main/.* ## on pull_request diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index b4e225e6..a69a4971 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -2,7 +2,7 @@ name: Docs on: push: - branches: [master] + branches: [main] env: BUILDER_THREADS: '1' From 46961cfdf72a3b5d54b241a41d9f2496c6dc6229 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 29 May 2023 19:46:28 +0200 Subject: [PATCH 13/15] Fix tests. --- .../src/shared_bus/blocking/i2c.rs | 5 ++--- .../src/shared_bus/blocking/spi.rs | 5 ++--- embassy-hal-common/src/atomic_ring_buffer.rs | 2 -- embassy-nrf/src/time_driver.rs | 2 +- embassy-stm32/src/flash/common.rs | 2 +- embassy-stm32/src/pwm/complementary_pwm.rs | 14 +++++++------- embassy-time/Cargo.toml | 2 +- embassy-time/src/driver.rs | 2 +- embassy-time/src/queue_generic.rs | 15 +++++++++------ embassy-time/src/timer.rs | 1 - 10 files changed, 24 insertions(+), 26 deletions(-) diff --git a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs index 1fe520e6..af73df05 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs @@ -2,13 +2,12 @@ //! //! # Example (nrf52) //! -//! ```rust +//! ```rust,ignore //! use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; //! use embassy_sync::blocking_mutex::{NoopMutex, raw::NoopRawMutex}; //! //! static I2C_BUS: StaticCell>>> = StaticCell::new(); -//! let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -//! let i2c = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, Config::default()); +//! let i2c = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, Config::default()); //! let i2c_bus = NoopMutex::new(RefCell::new(i2c)); //! let i2c_bus = I2C_BUS.init(i2c_bus); //! diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs index 7982ffb6..22e013be 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs @@ -2,13 +2,12 @@ //! //! # Example (nrf52) //! -//! ```rust +//! ```rust,ignore //! use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; //! use embassy_sync::blocking_mutex::{NoopMutex, raw::NoopRawMutex}; //! //! static SPI_BUS: StaticCell>>> = StaticCell::new(); -//! let irq = interrupt::take!(SPIM3); -//! let spi = Spim::new_txonly(p.SPI3, irq, p.P0_15, p.P0_18, Config::default()); +//! let spi = Spim::new_txonly(p.SPI3, Irqs, p.P0_15, p.P0_18, Config::default()); //! let spi_bus = NoopMutex::new(RefCell::new(spi)); //! let spi_bus = SPI_BUS.init(spi_bus); //! diff --git a/embassy-hal-common/src/atomic_ring_buffer.rs b/embassy-hal-common/src/atomic_ring_buffer.rs index 0eb39cb3..ea84925c 100644 --- a/embassy-hal-common/src/atomic_ring_buffer.rs +++ b/embassy-hal-common/src/atomic_ring_buffer.rs @@ -458,8 +458,6 @@ mod tests { #[test] fn push_slices() { - init(); - let mut b = [0; 4]; let rb = RingBuffer::new(); unsafe { diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index bc2c8a3c..c82c238c 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -67,7 +67,7 @@ fn compare_n(n: usize) -> u32 { 1 << (n + 16) } -#[cfg(tests)] +#[cfg(test)] mod test { use super::*; diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 6c191290..c6cdc574 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -163,7 +163,7 @@ pub(super) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector bank_offset = 0; } - if address < region.end() { + if address >= region.base && address < region.end() { let index_in_region = (address - region.base) / region.erase_size; return FlashSector { bank: region.bank, diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs index 3f8b43cf..cfb79947 100644 --- a/embassy-stm32/src/pwm/complementary_pwm.rs +++ b/embassy-stm32/src/pwm/complementary_pwm.rs @@ -209,39 +209,39 @@ mod tests { #[test] fn test_compute_dead_time_value() { - struct test_run { + struct TestRun { value: u16, ckd: Ckd, bits: u8, } let fn_results = [ - test_run { + TestRun { value: 1, ckd: Ckd::DIV1, bits: 1, }, - test_run { + TestRun { value: 125, ckd: Ckd::DIV1, bits: 125, }, - test_run { + TestRun { value: 245, ckd: Ckd::DIV1, bits: 64 + 245 / 2, }, - test_run { + TestRun { value: 255, ckd: Ckd::DIV2, bits: 127, }, - test_run { + TestRun { value: 400, ckd: Ckd::DIV1, bits: 32 + (400u16 / 8) as u8, }, - test_run { + TestRun { value: 600, ckd: Ckd::DIV4, bits: 64 + (600u16 / 8) as u8, diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index c4edbd38..857da546 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -169,4 +169,4 @@ wasm-timer = { version = "0.2.5", optional = true } [dev-dependencies] serial_test = "0.9" critical-section = { version = "1.1", features = ["std"] } - +embassy-executor = { version = "0.2.0", path = "../embassy-executor", features = ["nightly"] } diff --git a/embassy-time/src/driver.rs b/embassy-time/src/driver.rs index 5c2ad3b2..d6436369 100644 --- a/embassy-time/src/driver.rs +++ b/embassy-time/src/driver.rs @@ -49,7 +49,7 @@ //! fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { //! todo!() //! } -//! fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { +//! fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { //! todo!() //! } //! } diff --git a/embassy-time/src/queue_generic.rs b/embassy-time/src/queue_generic.rs index 64a8af4b..4795eb2f 100644 --- a/embassy-time/src/queue_generic.rs +++ b/embassy-time/src/queue_generic.rs @@ -183,7 +183,6 @@ mod tests { use serial_test::serial; - use super::InnerQueue; use crate::driver::{AlarmHandle, Driver}; use crate::queue_generic::QUEUE; use crate::Instant; @@ -317,14 +316,18 @@ mod tests { fn setup() { DRIVER.reset(); - - QUEUE.inner.lock(|inner| { - *inner.borrow_mut() = InnerQueue::new(); - }); + critical_section::with(|cs| *QUEUE.inner.borrow_ref_mut(cs) = None); } fn queue_len() -> usize { - QUEUE.inner.lock(|inner| inner.borrow().queue.iter().count()) + critical_section::with(|cs| { + QUEUE + .inner + .borrow_ref(cs) + .as_ref() + .map(|inner| inner.queue.iter().count()) + .unwrap_or(0) + }) } #[test] diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index 52620d23..d3d1f9f5 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -109,7 +109,6 @@ impl Future for Timer { /// # #![feature(type_alias_impl_trait)] /// # /// use embassy_time::{Duration, Ticker}; -/// use futures::StreamExt; /// # fn foo(){} /// /// #[embassy_executor::task] From 421ee4dfbfbbdc007265498d4f529687c16d89af Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 29 May 2023 19:46:46 +0200 Subject: [PATCH 14/15] ci: add stable build, add tests. --- .github/ci/build-stable.sh | 16 ++++++++++++++++ .github/ci/{rust.sh => build.sh} | 2 -- .github/ci/test.sh | 28 ++++++++++++++++++++++++++++ ci_stable.sh | 3 --- 4 files changed, 44 insertions(+), 5 deletions(-) create mode 100755 .github/ci/build-stable.sh rename .github/ci/{rust.sh => build.sh} (95%) create mode 100755 .github/ci/test.sh diff --git a/.github/ci/build-stable.sh b/.github/ci/build-stable.sh new file mode 100755 index 00000000..0dadd610 --- /dev/null +++ b/.github/ci/build-stable.sh @@ -0,0 +1,16 @@ +#!/bin/bash +## on push branch~=gh-readonly-queue/main/.* +## on pull_request + +set -euo pipefail + +export RUSTUP_HOME=/ci/cache/rustup +export CARGO_HOME=/ci/cache/cargo +export CARGO_TARGET_DIR=/ci/cache/target + +hashtime restore /ci/cache/filetime.json || true +hashtime save /ci/cache/filetime.json + +sed -i 's/channel.*/channel = "stable"/g' rust-toolchain.toml + +./ci_stable.sh diff --git a/.github/ci/rust.sh b/.github/ci/build.sh similarity index 95% rename from .github/ci/rust.sh rename to .github/ci/build.sh index db1fc853..1c3a7f3b 100755 --- a/.github/ci/rust.sh +++ b/.github/ci/build.sh @@ -4,8 +4,6 @@ set -euo pipefail -echo Hello World! - export RUSTUP_HOME=/ci/cache/rustup export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target diff --git a/.github/ci/test.sh b/.github/ci/test.sh new file mode 100755 index 00000000..a7140cfd --- /dev/null +++ b/.github/ci/test.sh @@ -0,0 +1,28 @@ +#!/bin/bash +## on push branch~=gh-readonly-queue/main/.* +## on pull_request + +set -euo pipefail + +export RUSTUP_HOME=/ci/cache/rustup +export CARGO_HOME=/ci/cache/cargo +export CARGO_TARGET_DIR=/ci/cache/target + +hashtime restore /ci/cache/filetime.json || true +hashtime save /ci/cache/filetime.json + +cargo test --manifest-path ./embassy-sync/Cargo.toml +cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml +cargo test --manifest-path ./embassy-hal-common/Cargo.toml +cargo test --manifest-path ./embassy-time/Cargo.toml --features generic-queue + +cargo test --manifest-path ./embassy-boot/boot/Cargo.toml +cargo test --manifest-path ./embassy-boot/boot/Cargo.toml --features nightly +cargo test --manifest-path ./embassy-boot/boot/Cargo.toml --features nightly,ed25519-dalek +cargo test --manifest-path ./embassy-boot/boot/Cargo.toml --features nightly,ed25519-salty + +#cargo test --manifest-path ./embassy-nrf/Cargo.toml --no-default-features --features nightly,nrf52840,time-driver-rtc1 ## broken doctests + +cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f429vg,exti,time-driver-any,exti +cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f732ze,exti,time-driver-any,exti +cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f769ni,exti,time-driver-any,exti diff --git a/ci_stable.sh b/ci_stable.sh index 55a2f89a..a67087ff 100755 --- a/ci_stable.sh +++ b/ci_stable.sh @@ -2,12 +2,9 @@ set -euo pipefail -export CARGO_TARGET_DIR=$PWD/target_ci_stable export RUSTFLAGS=-Dwarnings export DEFMT_LOG=trace -sed -i 's/channel.*/channel = "stable"/g' rust-toolchain.toml - cargo batch \ --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ From c844894a6e25bbf38c10ed7e60ee554e565b56b1 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Mon, 29 May 2023 21:29:13 +0200 Subject: [PATCH 15/15] Split the FirmwareUpdater into blocking and async --- embassy-boot/boot/src/firmware_updater.rs | 543 ------------------ .../boot/src/firmware_updater/asynch.rs | 251 ++++++++ .../boot/src/firmware_updater/blocking.rs | 221 +++++++ embassy-boot/boot/src/firmware_updater/mod.rs | 71 +++ 4 files changed, 543 insertions(+), 543 deletions(-) delete mode 100644 embassy-boot/boot/src/firmware_updater.rs create mode 100644 embassy-boot/boot/src/firmware_updater/asynch.rs create mode 100644 embassy-boot/boot/src/firmware_updater/blocking.rs create mode 100644 embassy-boot/boot/src/firmware_updater/mod.rs diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs deleted file mode 100644 index aeea206f..00000000 --- a/embassy-boot/boot/src/firmware_updater.rs +++ /dev/null @@ -1,543 +0,0 @@ -use digest::Digest; -use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; -#[cfg(feature = "nightly")] -use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash; - -use crate::{Partition, State, BOOT_MAGIC, SWAP_MAGIC}; - -/// Errors returned by FirmwareUpdater -#[derive(Debug)] -pub enum FirmwareUpdaterError { - /// Error from flash. - Flash(NorFlashErrorKind), - /// Signature errors. - Signature(signature::Error), -} - -#[cfg(feature = "defmt")] -impl defmt::Format for FirmwareUpdaterError { - fn format(&self, fmt: defmt::Formatter) { - match self { - FirmwareUpdaterError::Flash(_) => defmt::write!(fmt, "FirmwareUpdaterError::Flash(_)"), - FirmwareUpdaterError::Signature(_) => defmt::write!(fmt, "FirmwareUpdaterError::Signature(_)"), - } - } -} - -impl From for FirmwareUpdaterError -where - E: NorFlashError, -{ - fn from(error: E) -> Self { - FirmwareUpdaterError::Flash(error.kind()) - } -} - -/// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to -/// 'mess up' the internal bootloader state -pub struct FirmwareUpdater { - state: Partition, - dfu: Partition, -} - -#[cfg(target_os = "none")] -impl Default for FirmwareUpdater { - fn default() -> Self { - extern "C" { - static __bootloader_state_start: u32; - static __bootloader_state_end: u32; - static __bootloader_dfu_start: u32; - static __bootloader_dfu_end: u32; - } - - let dfu = unsafe { - Partition::new( - &__bootloader_dfu_start as *const u32 as u32, - &__bootloader_dfu_end as *const u32 as u32, - ) - }; - let state = unsafe { - Partition::new( - &__bootloader_state_start as *const u32 as u32, - &__bootloader_state_end as *const u32 as u32, - ) - }; - - trace!("DFU: 0x{:x} - 0x{:x}", dfu.from, dfu.to); - trace!("STATE: 0x{:x} - 0x{:x}", state.from, state.to); - FirmwareUpdater::new(dfu, state) - } -} - -impl FirmwareUpdater { - /// Create a firmware updater instance with partition ranges for the update and state partitions. - pub const fn new(dfu: Partition, state: Partition) -> Self { - Self { dfu, state } - } - - /// Obtain the current state. - /// - /// This is useful to check if the bootloader has just done a swap, in order - /// to do verifications and self-tests of the new image before calling - /// `mark_booted`. - #[cfg(feature = "nightly")] - pub async fn get_state( - &mut self, - state_flash: &mut F, - aligned: &mut [u8], - ) -> Result { - self.state.read(state_flash, 0, aligned).await?; - - if !aligned.iter().any(|&b| b != SWAP_MAGIC) { - Ok(State::Swap) - } else { - Ok(State::Boot) - } - } - - /// Verify the DFU given a public key. If there is an error then DO NOT - /// proceed with updating the firmware as it must be signed with a - /// corresponding private key (otherwise it could be malicious firmware). - /// - /// Mark to trigger firmware swap on next boot if verify suceeds. - /// - /// If the "ed25519-salty" feature is set (or another similar feature) then the signature is expected to have - /// been generated from a SHA-512 digest of the firmware bytes. - /// - /// If no signature feature is set then this method will always return a - /// signature error. - /// - /// # Safety - /// - /// The `_aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being read from - /// and written to. - #[cfg(all(feature = "_verify", feature = "nightly"))] - pub async fn verify_and_mark_updated( - &mut self, - _state_and_dfu_flash: &mut F, - _public_key: &[u8], - _signature: &[u8], - _update_len: u32, - _aligned: &mut [u8], - ) -> Result<(), FirmwareUpdaterError> { - assert_eq!(_aligned.len(), F::WRITE_SIZE); - assert!(_update_len <= self.dfu.size()); - - #[cfg(feature = "ed25519-dalek")] - { - use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; - - use crate::digest_adapters::ed25519_dalek::Sha512; - - let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); - - let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; - let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; - - let mut message = [0; 64]; - self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message) - .await?; - - public_key.verify(&message, &signature).map_err(into_signature_error)? - } - #[cfg(feature = "ed25519-salty")] - { - use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH}; - use salty::{PublicKey, Signature}; - - use crate::digest_adapters::salty::Sha512; - - fn into_signature_error(_: E) -> FirmwareUpdaterError { - FirmwareUpdaterError::Signature(signature::Error::default()) - } - - let public_key: [u8; PUBLICKEY_SERIALIZED_LENGTH] = _public_key.try_into().map_err(into_signature_error)?; - let public_key = PublicKey::try_from(&public_key).map_err(into_signature_error)?; - let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?; - let signature = Signature::try_from(&signature).map_err(into_signature_error)?; - - let mut message = [0; 64]; - self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message) - .await?; - - let r = public_key.verify(&message, &signature); - trace!( - "Verifying with public key {}, signature {} and message {} yields ok: {}", - public_key.to_bytes(), - signature.to_bytes(), - message, - r.is_ok() - ); - r.map_err(into_signature_error)? - } - - self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await - } - - /// Verify the update in DFU with any digest. - #[cfg(feature = "nightly")] - pub async fn hash( - &mut self, - dfu_flash: &mut F, - update_len: u32, - chunk_buf: &mut [u8], - output: &mut [u8], - ) -> Result<(), FirmwareUpdaterError> { - let mut digest = D::new(); - for offset in (0..update_len).step_by(chunk_buf.len()) { - self.dfu.read(dfu_flash, offset, chunk_buf).await?; - let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len()); - digest.update(&chunk_buf[..len]); - } - output.copy_from_slice(digest.finalize().as_slice()); - Ok(()) - } - - /// Mark to trigger firmware swap on next boot. - /// - /// # Safety - /// - /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. - #[cfg(all(feature = "nightly", not(feature = "_verify")))] - pub async fn mark_updated( - &mut self, - state_flash: &mut F, - aligned: &mut [u8], - ) -> Result<(), FirmwareUpdaterError> { - assert_eq!(aligned.len(), F::WRITE_SIZE); - self.set_magic(aligned, SWAP_MAGIC, state_flash).await - } - - /// Mark firmware boot successful and stop rollback on reset. - /// - /// # Safety - /// - /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. - #[cfg(feature = "nightly")] - pub async fn mark_booted( - &mut self, - state_flash: &mut F, - aligned: &mut [u8], - ) -> Result<(), FirmwareUpdaterError> { - assert_eq!(aligned.len(), F::WRITE_SIZE); - self.set_magic(aligned, BOOT_MAGIC, state_flash).await - } - - #[cfg(feature = "nightly")] - async fn set_magic( - &mut self, - aligned: &mut [u8], - magic: u8, - state_flash: &mut F, - ) -> Result<(), FirmwareUpdaterError> { - self.state.read(state_flash, 0, aligned).await?; - - if aligned.iter().any(|&b| b != magic) { - // Read progress validity - self.state.read(state_flash, F::WRITE_SIZE as u32, aligned).await?; - - // FIXME: Do not make this assumption. - const STATE_ERASE_VALUE: u8 = 0xFF; - - if aligned.iter().any(|&b| b != STATE_ERASE_VALUE) { - // The current progress validity marker is invalid - } else { - // Invalidate progress - aligned.fill(!STATE_ERASE_VALUE); - self.state.write(state_flash, F::WRITE_SIZE as u32, aligned).await?; - } - - // Clear magic and progress - self.state.wipe(state_flash).await?; - - // Set magic - aligned.fill(magic); - self.state.write(state_flash, 0, aligned).await?; - } - Ok(()) - } - - /// Write data to a flash page. - /// - /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. - /// - /// # Safety - /// - /// Failing to meet alignment and size requirements may result in a panic. - #[cfg(feature = "nightly")] - pub async fn write_firmware( - &mut self, - offset: usize, - data: &[u8], - dfu_flash: &mut F, - ) -> Result<(), FirmwareUpdaterError> { - assert!(data.len() >= F::ERASE_SIZE); - - self.dfu - .erase(dfu_flash, offset as u32, (offset + data.len()) as u32) - .await?; - - self.dfu.write(dfu_flash, offset as u32, data).await?; - - Ok(()) - } - - /// Prepare for an incoming DFU update by erasing the entire DFU area and - /// returning its `Partition`. - /// - /// Using this instead of `write_firmware` allows for an optimized API in - /// exchange for added complexity. - #[cfg(feature = "nightly")] - pub async fn prepare_update( - &mut self, - dfu_flash: &mut F, - ) -> Result { - self.dfu.wipe(dfu_flash).await?; - - Ok(self.dfu) - } - - // - // Blocking API - // - - /// Obtain the current state. - /// - /// This is useful to check if the bootloader has just done a swap, in order - /// to do verifications and self-tests of the new image before calling - /// `mark_booted`. - pub fn get_state_blocking( - &mut self, - state_flash: &mut F, - aligned: &mut [u8], - ) -> Result { - self.state.read_blocking(state_flash, 0, aligned)?; - - if !aligned.iter().any(|&b| b != SWAP_MAGIC) { - Ok(State::Swap) - } else { - Ok(State::Boot) - } - } - - /// Verify the DFU given a public key. If there is an error then DO NOT - /// proceed with updating the firmware as it must be signed with a - /// corresponding private key (otherwise it could be malicious firmware). - /// - /// Mark to trigger firmware swap on next boot if verify suceeds. - /// - /// If the "ed25519-salty" feature is set (or another similar feature) then the signature is expected to have - /// been generated from a SHA-512 digest of the firmware bytes. - /// - /// If no signature feature is set then this method will always return a - /// signature error. - /// - /// # Safety - /// - /// The `_aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being read from - /// and written to. - #[cfg(feature = "_verify")] - pub fn verify_and_mark_updated_blocking( - &mut self, - _state_and_dfu_flash: &mut F, - _public_key: &[u8], - _signature: &[u8], - _update_len: u32, - _aligned: &mut [u8], - ) -> Result<(), FirmwareUpdaterError> { - assert_eq!(_aligned.len(), F::WRITE_SIZE); - assert!(_update_len <= self.dfu.size()); - - #[cfg(feature = "ed25519-dalek")] - { - use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; - - use crate::digest_adapters::ed25519_dalek::Sha512; - - let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); - - let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; - let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; - - let mut message = [0; 64]; - self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?; - - public_key.verify(&message, &signature).map_err(into_signature_error)? - } - #[cfg(feature = "ed25519-salty")] - { - use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH}; - use salty::{PublicKey, Signature}; - - use crate::digest_adapters::salty::Sha512; - - fn into_signature_error(_: E) -> FirmwareUpdaterError { - FirmwareUpdaterError::Signature(signature::Error::default()) - } - - let public_key: [u8; PUBLICKEY_SERIALIZED_LENGTH] = _public_key.try_into().map_err(into_signature_error)?; - let public_key = PublicKey::try_from(&public_key).map_err(into_signature_error)?; - let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?; - let signature = Signature::try_from(&signature).map_err(into_signature_error)?; - - let mut message = [0; 64]; - self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?; - - let r = public_key.verify(&message, &signature); - trace!( - "Verifying with public key {}, signature {} and message {} yields ok: {}", - public_key.to_bytes(), - signature.to_bytes(), - message, - r.is_ok() - ); - r.map_err(into_signature_error)? - } - - self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash) - } - - /// Verify the update in DFU with any digest. - pub fn hash_blocking( - &mut self, - dfu_flash: &mut F, - update_len: u32, - chunk_buf: &mut [u8], - output: &mut [u8], - ) -> Result<(), FirmwareUpdaterError> { - let mut digest = D::new(); - for offset in (0..update_len).step_by(chunk_buf.len()) { - self.dfu.read_blocking(dfu_flash, offset, chunk_buf)?; - let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len()); - digest.update(&chunk_buf[..len]); - } - output.copy_from_slice(digest.finalize().as_slice()); - Ok(()) - } - - /// Mark to trigger firmware swap on next boot. - /// - /// # Safety - /// - /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. - #[cfg(not(feature = "_verify"))] - pub fn mark_updated_blocking( - &mut self, - state_flash: &mut F, - aligned: &mut [u8], - ) -> Result<(), FirmwareUpdaterError> { - assert_eq!(aligned.len(), F::WRITE_SIZE); - self.set_magic_blocking(aligned, SWAP_MAGIC, state_flash) - } - - /// Mark firmware boot successful and stop rollback on reset. - /// - /// # Safety - /// - /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. - pub fn mark_booted_blocking( - &mut self, - state_flash: &mut F, - aligned: &mut [u8], - ) -> Result<(), FirmwareUpdaterError> { - assert_eq!(aligned.len(), F::WRITE_SIZE); - self.set_magic_blocking(aligned, BOOT_MAGIC, state_flash) - } - - fn set_magic_blocking( - &mut self, - aligned: &mut [u8], - magic: u8, - state_flash: &mut F, - ) -> Result<(), FirmwareUpdaterError> { - self.state.read_blocking(state_flash, 0, aligned)?; - - if aligned.iter().any(|&b| b != magic) { - // Read progress validity - self.state.read_blocking(state_flash, F::WRITE_SIZE as u32, aligned)?; - - // FIXME: Do not make this assumption. - const STATE_ERASE_VALUE: u8 = 0xFF; - - if aligned.iter().any(|&b| b != STATE_ERASE_VALUE) { - // The current progress validity marker is invalid - } else { - // Invalidate progress - aligned.fill(!STATE_ERASE_VALUE); - self.state.write_blocking(state_flash, F::WRITE_SIZE as u32, aligned)?; - } - - // Clear magic and progress - self.state.wipe_blocking(state_flash)?; - - // Set magic - aligned.fill(magic); - self.state.write_blocking(state_flash, 0, aligned)?; - } - Ok(()) - } - - /// Write data to a flash page. - /// - /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. - /// - /// # Safety - /// - /// Failing to meet alignment and size requirements may result in a panic. - pub fn write_firmware_blocking( - &mut self, - offset: usize, - data: &[u8], - dfu_flash: &mut F, - ) -> Result<(), FirmwareUpdaterError> { - assert!(data.len() >= F::ERASE_SIZE); - - self.dfu - .erase_blocking(dfu_flash, offset as u32, (offset + data.len()) as u32)?; - - self.dfu.write_blocking(dfu_flash, offset as u32, data)?; - - Ok(()) - } - - /// Prepare for an incoming DFU update by erasing the entire DFU area and - /// returning its `Partition`. - /// - /// Using this instead of `write_firmware_blocking` allows for an optimized - /// API in exchange for added complexity. - pub fn prepare_update_blocking(&mut self, flash: &mut F) -> Result { - self.dfu.wipe_blocking(flash)?; - - Ok(self.dfu) - } -} - -#[cfg(test)] -mod tests { - use futures::executor::block_on; - use sha1::{Digest, Sha1}; - - use super::*; - use crate::mem_flash::MemFlash; - - #[test] - #[cfg(feature = "nightly")] - fn can_verify_sha1() { - const STATE: Partition = Partition::new(0, 4096); - const DFU: Partition = Partition::new(65536, 131072); - - let mut flash = MemFlash::<131072, 4096, 8>::default(); - - let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66]; - let mut to_write = [0; 4096]; - to_write[..7].copy_from_slice(update.as_slice()); - - let mut updater = FirmwareUpdater::new(DFU, STATE); - block_on(updater.write_firmware(0, to_write.as_slice(), &mut flash)).unwrap(); - let mut chunk_buf = [0; 2]; - let mut hash = [0; 20]; - block_on(updater.hash::<_, Sha1>(&mut flash, update.len() as u32, &mut chunk_buf, &mut hash)).unwrap(); - - assert_eq!(Sha1::digest(update).as_slice(), hash); - } -} diff --git a/embassy-boot/boot/src/firmware_updater/asynch.rs b/embassy-boot/boot/src/firmware_updater/asynch.rs new file mode 100644 index 00000000..bdd03bff --- /dev/null +++ b/embassy-boot/boot/src/firmware_updater/asynch.rs @@ -0,0 +1,251 @@ +use digest::Digest; +use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash; + +use crate::{FirmwareUpdater, FirmwareUpdaterError, Partition, State, BOOT_MAGIC, SWAP_MAGIC}; + +impl FirmwareUpdater { + /// Obtain the current state. + /// + /// This is useful to check if the bootloader has just done a swap, in order + /// to do verifications and self-tests of the new image before calling + /// `mark_booted`. + pub async fn get_state( + &mut self, + state_flash: &mut F, + aligned: &mut [u8], + ) -> Result { + self.state.read(state_flash, 0, aligned).await?; + + if !aligned.iter().any(|&b| b != SWAP_MAGIC) { + Ok(State::Swap) + } else { + Ok(State::Boot) + } + } + + /// Verify the DFU given a public key. If there is an error then DO NOT + /// proceed with updating the firmware as it must be signed with a + /// corresponding private key (otherwise it could be malicious firmware). + /// + /// Mark to trigger firmware swap on next boot if verify suceeds. + /// + /// If the "ed25519-salty" feature is set (or another similar feature) then the signature is expected to have + /// been generated from a SHA-512 digest of the firmware bytes. + /// + /// If no signature feature is set then this method will always return a + /// signature error. + /// + /// # Safety + /// + /// The `_aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being read from + /// and written to. + #[cfg(all(feature = "_verify", feature = "nightly"))] + pub async fn verify_and_mark_updated( + &mut self, + _state_and_dfu_flash: &mut F, + _public_key: &[u8], + _signature: &[u8], + _update_len: u32, + _aligned: &mut [u8], + ) -> Result<(), FirmwareUpdaterError> { + assert_eq!(_aligned.len(), F::WRITE_SIZE); + assert!(_update_len <= self.dfu.size()); + + #[cfg(feature = "ed25519-dalek")] + { + use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; + + use crate::digest_adapters::ed25519_dalek::Sha512; + + let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); + + let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; + let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; + + let mut message = [0; 64]; + self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message) + .await?; + + public_key.verify(&message, &signature).map_err(into_signature_error)? + } + #[cfg(feature = "ed25519-salty")] + { + use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH}; + use salty::{PublicKey, Signature}; + + use crate::digest_adapters::salty::Sha512; + + fn into_signature_error(_: E) -> FirmwareUpdaterError { + FirmwareUpdaterError::Signature(signature::Error::default()) + } + + let public_key: [u8; PUBLICKEY_SERIALIZED_LENGTH] = _public_key.try_into().map_err(into_signature_error)?; + let public_key = PublicKey::try_from(&public_key).map_err(into_signature_error)?; + let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?; + let signature = Signature::try_from(&signature).map_err(into_signature_error)?; + + let mut message = [0; 64]; + self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message) + .await?; + + let r = public_key.verify(&message, &signature); + trace!( + "Verifying with public key {}, signature {} and message {} yields ok: {}", + public_key.to_bytes(), + signature.to_bytes(), + message, + r.is_ok() + ); + r.map_err(into_signature_error)? + } + + self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await + } + + /// Verify the update in DFU with any digest. + pub async fn hash( + &mut self, + dfu_flash: &mut F, + update_len: u32, + chunk_buf: &mut [u8], + output: &mut [u8], + ) -> Result<(), FirmwareUpdaterError> { + let mut digest = D::new(); + for offset in (0..update_len).step_by(chunk_buf.len()) { + self.dfu.read(dfu_flash, offset, chunk_buf).await?; + let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len()); + digest.update(&chunk_buf[..len]); + } + output.copy_from_slice(digest.finalize().as_slice()); + Ok(()) + } + + /// Mark to trigger firmware swap on next boot. + /// + /// # Safety + /// + /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. + #[cfg(all(feature = "nightly", not(feature = "_verify")))] + pub async fn mark_updated( + &mut self, + state_flash: &mut F, + aligned: &mut [u8], + ) -> Result<(), FirmwareUpdaterError> { + assert_eq!(aligned.len(), F::WRITE_SIZE); + self.set_magic(aligned, SWAP_MAGIC, state_flash).await + } + + /// Mark firmware boot successful and stop rollback on reset. + /// + /// # Safety + /// + /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. + pub async fn mark_booted( + &mut self, + state_flash: &mut F, + aligned: &mut [u8], + ) -> Result<(), FirmwareUpdaterError> { + assert_eq!(aligned.len(), F::WRITE_SIZE); + self.set_magic(aligned, BOOT_MAGIC, state_flash).await + } + + async fn set_magic( + &mut self, + aligned: &mut [u8], + magic: u8, + state_flash: &mut F, + ) -> Result<(), FirmwareUpdaterError> { + self.state.read(state_flash, 0, aligned).await?; + + if aligned.iter().any(|&b| b != magic) { + // Read progress validity + self.state.read(state_flash, F::WRITE_SIZE as u32, aligned).await?; + + // FIXME: Do not make this assumption. + const STATE_ERASE_VALUE: u8 = 0xFF; + + if aligned.iter().any(|&b| b != STATE_ERASE_VALUE) { + // The current progress validity marker is invalid + } else { + // Invalidate progress + aligned.fill(!STATE_ERASE_VALUE); + self.state.write(state_flash, F::WRITE_SIZE as u32, aligned).await?; + } + + // Clear magic and progress + self.state.wipe(state_flash).await?; + + // Set magic + aligned.fill(magic); + self.state.write(state_flash, 0, aligned).await?; + } + Ok(()) + } + + /// Write data to a flash page. + /// + /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. + /// + /// # Safety + /// + /// Failing to meet alignment and size requirements may result in a panic. + pub async fn write_firmware( + &mut self, + offset: usize, + data: &[u8], + dfu_flash: &mut F, + ) -> Result<(), FirmwareUpdaterError> { + assert!(data.len() >= F::ERASE_SIZE); + + self.dfu + .erase(dfu_flash, offset as u32, (offset + data.len()) as u32) + .await?; + + self.dfu.write(dfu_flash, offset as u32, data).await?; + + Ok(()) + } + + /// Prepare for an incoming DFU update by erasing the entire DFU area and + /// returning its `Partition`. + /// + /// Using this instead of `write_firmware` allows for an optimized API in + /// exchange for added complexity. + pub async fn prepare_update( + &mut self, + dfu_flash: &mut F, + ) -> Result { + self.dfu.wipe(dfu_flash).await?; + + Ok(self.dfu) + } +} + +#[cfg(test)] +mod tests { + use futures::executor::block_on; + use sha1::{Digest, Sha1}; + + use super::*; + use crate::mem_flash::MemFlash; + + #[test] + fn can_verify_sha1() { + const STATE: Partition = Partition::new(0, 4096); + const DFU: Partition = Partition::new(65536, 131072); + + let mut flash = MemFlash::<131072, 4096, 8>::default(); + + let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66]; + let mut to_write = [0; 4096]; + to_write[..7].copy_from_slice(update.as_slice()); + + let mut updater = FirmwareUpdater::new(DFU, STATE); + block_on(updater.write_firmware(0, to_write.as_slice(), &mut flash)).unwrap(); + let mut chunk_buf = [0; 2]; + let mut hash = [0; 20]; + block_on(updater.hash::<_, Sha1>(&mut flash, update.len() as u32, &mut chunk_buf, &mut hash)).unwrap(); + + assert_eq!(Sha1::digest(update).as_slice(), hash); + } +} diff --git a/embassy-boot/boot/src/firmware_updater/blocking.rs b/embassy-boot/boot/src/firmware_updater/blocking.rs new file mode 100644 index 00000000..50caaf08 --- /dev/null +++ b/embassy-boot/boot/src/firmware_updater/blocking.rs @@ -0,0 +1,221 @@ +use digest::Digest; +use embedded_storage::nor_flash::NorFlash; + +use crate::{FirmwareUpdater, FirmwareUpdaterError, Partition, State, BOOT_MAGIC, SWAP_MAGIC}; + +impl FirmwareUpdater { + /// Create a firmware updater instance with partition ranges for the update and state partitions. + pub const fn new(dfu: Partition, state: Partition) -> Self { + Self { dfu, state } + } + + /// Obtain the current state. + /// + /// This is useful to check if the bootloader has just done a swap, in order + /// to do verifications and self-tests of the new image before calling + /// `mark_booted`. + pub fn get_state_blocking( + &mut self, + state_flash: &mut F, + aligned: &mut [u8], + ) -> Result { + self.state.read_blocking(state_flash, 0, aligned)?; + + if !aligned.iter().any(|&b| b != SWAP_MAGIC) { + Ok(State::Swap) + } else { + Ok(State::Boot) + } + } + + /// Verify the DFU given a public key. If there is an error then DO NOT + /// proceed with updating the firmware as it must be signed with a + /// corresponding private key (otherwise it could be malicious firmware). + /// + /// Mark to trigger firmware swap on next boot if verify suceeds. + /// + /// If the "ed25519-salty" feature is set (or another similar feature) then the signature is expected to have + /// been generated from a SHA-512 digest of the firmware bytes. + /// + /// If no signature feature is set then this method will always return a + /// signature error. + /// + /// # Safety + /// + /// The `_aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being read from + /// and written to. + #[cfg(feature = "_verify")] + pub fn verify_and_mark_updated_blocking( + &mut self, + _state_and_dfu_flash: &mut F, + _public_key: &[u8], + _signature: &[u8], + _update_len: u32, + _aligned: &mut [u8], + ) -> Result<(), FirmwareUpdaterError> { + assert_eq!(_aligned.len(), F::WRITE_SIZE); + assert!(_update_len <= self.dfu.size()); + + #[cfg(feature = "ed25519-dalek")] + { + use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; + + use crate::digest_adapters::ed25519_dalek::Sha512; + + let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); + + let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; + let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; + + let mut message = [0; 64]; + self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?; + + public_key.verify(&message, &signature).map_err(into_signature_error)? + } + #[cfg(feature = "ed25519-salty")] + { + use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH}; + use salty::{PublicKey, Signature}; + + use crate::digest_adapters::salty::Sha512; + + fn into_signature_error(_: E) -> FirmwareUpdaterError { + FirmwareUpdaterError::Signature(signature::Error::default()) + } + + let public_key: [u8; PUBLICKEY_SERIALIZED_LENGTH] = _public_key.try_into().map_err(into_signature_error)?; + let public_key = PublicKey::try_from(&public_key).map_err(into_signature_error)?; + let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?; + let signature = Signature::try_from(&signature).map_err(into_signature_error)?; + + let mut message = [0; 64]; + self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?; + + let r = public_key.verify(&message, &signature); + trace!( + "Verifying with public key {}, signature {} and message {} yields ok: {}", + public_key.to_bytes(), + signature.to_bytes(), + message, + r.is_ok() + ); + r.map_err(into_signature_error)? + } + + self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash) + } + + /// Verify the update in DFU with any digest. + pub fn hash_blocking( + &mut self, + dfu_flash: &mut F, + update_len: u32, + chunk_buf: &mut [u8], + output: &mut [u8], + ) -> Result<(), FirmwareUpdaterError> { + let mut digest = D::new(); + for offset in (0..update_len).step_by(chunk_buf.len()) { + self.dfu.read_blocking(dfu_flash, offset, chunk_buf)?; + let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len()); + digest.update(&chunk_buf[..len]); + } + output.copy_from_slice(digest.finalize().as_slice()); + Ok(()) + } + + /// Mark to trigger firmware swap on next boot. + /// + /// # Safety + /// + /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. + #[cfg(not(feature = "_verify"))] + pub fn mark_updated_blocking( + &mut self, + state_flash: &mut F, + aligned: &mut [u8], + ) -> Result<(), FirmwareUpdaterError> { + assert_eq!(aligned.len(), F::WRITE_SIZE); + self.set_magic_blocking(aligned, SWAP_MAGIC, state_flash) + } + + /// Mark firmware boot successful and stop rollback on reset. + /// + /// # Safety + /// + /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. + pub fn mark_booted_blocking( + &mut self, + state_flash: &mut F, + aligned: &mut [u8], + ) -> Result<(), FirmwareUpdaterError> { + assert_eq!(aligned.len(), F::WRITE_SIZE); + self.set_magic_blocking(aligned, BOOT_MAGIC, state_flash) + } + + fn set_magic_blocking( + &mut self, + aligned: &mut [u8], + magic: u8, + state_flash: &mut F, + ) -> Result<(), FirmwareUpdaterError> { + self.state.read_blocking(state_flash, 0, aligned)?; + + if aligned.iter().any(|&b| b != magic) { + // Read progress validity + self.state.read_blocking(state_flash, F::WRITE_SIZE as u32, aligned)?; + + // FIXME: Do not make this assumption. + const STATE_ERASE_VALUE: u8 = 0xFF; + + if aligned.iter().any(|&b| b != STATE_ERASE_VALUE) { + // The current progress validity marker is invalid + } else { + // Invalidate progress + aligned.fill(!STATE_ERASE_VALUE); + self.state.write_blocking(state_flash, F::WRITE_SIZE as u32, aligned)?; + } + + // Clear magic and progress + self.state.wipe_blocking(state_flash)?; + + // Set magic + aligned.fill(magic); + self.state.write_blocking(state_flash, 0, aligned)?; + } + Ok(()) + } + + /// Write data to a flash page. + /// + /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. + /// + /// # Safety + /// + /// Failing to meet alignment and size requirements may result in a panic. + pub fn write_firmware_blocking( + &mut self, + offset: usize, + data: &[u8], + dfu_flash: &mut F, + ) -> Result<(), FirmwareUpdaterError> { + assert!(data.len() >= F::ERASE_SIZE); + + self.dfu + .erase_blocking(dfu_flash, offset as u32, (offset + data.len()) as u32)?; + + self.dfu.write_blocking(dfu_flash, offset as u32, data)?; + + Ok(()) + } + + /// Prepare for an incoming DFU update by erasing the entire DFU area and + /// returning its `Partition`. + /// + /// Using this instead of `write_firmware_blocking` allows for an optimized + /// API in exchange for added complexity. + pub fn prepare_update_blocking(&mut self, flash: &mut F) -> Result { + self.dfu.wipe_blocking(flash)?; + + Ok(self.dfu) + } +} diff --git a/embassy-boot/boot/src/firmware_updater/mod.rs b/embassy-boot/boot/src/firmware_updater/mod.rs new file mode 100644 index 00000000..e09f5eb6 --- /dev/null +++ b/embassy-boot/boot/src/firmware_updater/mod.rs @@ -0,0 +1,71 @@ +#[cfg(feature = "nightly")] +mod asynch; +mod blocking; + +use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; + +use crate::Partition; + +/// Errors returned by FirmwareUpdater +#[derive(Debug)] +pub enum FirmwareUpdaterError { + /// Error from flash. + Flash(NorFlashErrorKind), + /// Signature errors. + Signature(signature::Error), +} + +#[cfg(feature = "defmt")] +impl defmt::Format for FirmwareUpdaterError { + fn format(&self, fmt: defmt::Formatter) { + match self { + FirmwareUpdaterError::Flash(_) => defmt::write!(fmt, "FirmwareUpdaterError::Flash(_)"), + FirmwareUpdaterError::Signature(_) => defmt::write!(fmt, "FirmwareUpdaterError::Signature(_)"), + } + } +} + +impl From for FirmwareUpdaterError +where + E: NorFlashError, +{ + fn from(error: E) -> Self { + FirmwareUpdaterError::Flash(error.kind()) + } +} + +/// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to +/// 'mess up' the internal bootloader state +pub struct FirmwareUpdater { + state: Partition, + dfu: Partition, +} + +#[cfg(target_os = "none")] +impl Default for FirmwareUpdater { + fn default() -> Self { + extern "C" { + static __bootloader_state_start: u32; + static __bootloader_state_end: u32; + static __bootloader_dfu_start: u32; + static __bootloader_dfu_end: u32; + } + + let dfu = unsafe { + Partition::new( + &__bootloader_dfu_start as *const u32 as u32, + &__bootloader_dfu_end as *const u32 as u32, + ) + }; + let state = unsafe { + Partition::new( + &__bootloader_state_start as *const u32 as u32, + &__bootloader_state_end as *const u32 as u32, + ) + }; + + trace!("DFU: 0x{:x} - 0x{:x}", dfu.from, dfu.to); + trace!("STATE: 0x{:x} - 0x{:x}", state.from, state.to); + FirmwareUpdater::new(dfu, state) + } +}