diff options
| author | Dario Nieuwenhuis <[email protected]> | 2025-01-02 00:56:05 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-01-02 00:56:05 +0100 |
| commit | e7c3e1b2663b924f65d5ddf898030ddeffe6f368 (patch) | |
| tree | 2c2a1f10bdafbdd2bed2f655c544f91af4503417 | |
| parent | 667dfa34b525f727936d621ba91001fa25d80426 (diff) | |
| parent | c6e0508da0e5a8689b833c60e0d8e59b922ebd8f (diff) | |
Merge pull request #3703 from loftyinclination/main
add documentation for the BLE feature of the embassy-stm32-wpan crate
| -rw-r--r-- | embassy-stm32-wpan/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/consts.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/lib.rs | 46 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/sub/ble.rs | 29 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/sub/sys.rs | 11 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/tables.rs | 27 | ||||
| -rw-r--r-- | examples/stm32wb/src/bin/gatt_server.rs | 5 |
7 files changed, 106 insertions, 18 deletions
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 552d80982..74e7a67d9 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml | |||
| @@ -13,10 +13,10 @@ documentation = "https://docs.embassy.dev/embassy-stm32-wpan" | |||
| 13 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-wpan-v$VERSION/embassy-stm32-wpan/src/" | 13 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-wpan-v$VERSION/embassy-stm32-wpan/src/" |
| 14 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32-wpan/src/" | 14 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32-wpan/src/" |
| 15 | target = "thumbv7em-none-eabihf" | 15 | target = "thumbv7em-none-eabihf" |
| 16 | features = ["stm32wb55rg"] | 16 | features = ["stm32wb55rg", "ble", "mac"] |
| 17 | 17 | ||
| 18 | [package.metadata.docs.rs] | 18 | [package.metadata.docs.rs] |
| 19 | features = ["stm32wb55rg"] | 19 | features = ["stm32wb55rg", "ble", "mac"] |
| 20 | 20 | ||
| 21 | [dependencies] | 21 | [dependencies] |
| 22 | embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } | 22 | embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } |
diff --git a/embassy-stm32-wpan/src/consts.rs b/embassy-stm32-wpan/src/consts.rs index 6aaef1d35..e2ae6ca86 100644 --- a/embassy-stm32-wpan/src/consts.rs +++ b/embassy-stm32-wpan/src/consts.rs | |||
| @@ -69,7 +69,7 @@ pub const TL_CS_EVT_SIZE: usize = core::mem::size_of::<CsEvt>(); | |||
| 69 | * enough to store all asynchronous events received in between. | 69 | * enough to store all asynchronous events received in between. |
| 70 | * When CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE is set to 27, this allow to store three 255 bytes long asynchronous events | 70 | * When CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE is set to 27, this allow to store three 255 bytes long asynchronous events |
| 71 | * between the HCI command and its event. | 71 | * between the HCI command and its event. |
| 72 | * This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is to small, | 72 | * This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is too small, |
| 73 | * the system may hang if the queue is full with asynchronous events and the HCI layer is still waiting | 73 | * the system may hang if the queue is full with asynchronous events and the HCI layer is still waiting |
| 74 | * for a CC/CS event, In that case, the notification TL_BLE_HCI_ToNot() is called to indicate | 74 | * for a CC/CS event, In that case, the notification TL_BLE_HCI_ToNot() is called to indicate |
| 75 | * to the application a HCI command did not receive its command event within 30s (Default HCI Timeout). | 75 | * to the application a HCI command did not receive its command event within 30s (Default HCI Timeout). |
diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index fb34d4ba0..25e6d965a 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs | |||
| @@ -1,3 +1,16 @@ | |||
| 1 | //! The embassy-stm32-wpan crate aims to provide safe use of the commands necessary to interface | ||
| 2 | //! with the Cortex C0 CPU2 coprocessor of STM32WB microcontrollers. It implements safe wrappers | ||
| 3 | //! around the Transport Layer, and in particular the system, memory, BLE and Mac channels. | ||
| 4 | //! | ||
| 5 | //! # Design | ||
| 6 | //! | ||
| 7 | //! This crate loosely follows the Application Note 5289 "How to build wireless applications with | ||
| 8 | //! STM32WB MCUs"; several of the startup procedures laid out in Annex 14.1 are implemented using | ||
| 9 | //! inline copies of the code contained within the `stm32wb_copro` C library. | ||
| 10 | //! | ||
| 11 | //! BLE commands are implemented via use of the [stm32wb_hci] crate, for which the | ||
| 12 | //! [stm32wb_hci::Controller] trait has been implemented. | ||
| 13 | |||
| 1 | #![no_std] | 14 | #![no_std] |
| 2 | #![allow(async_fn_in_trait)] | 15 | #![allow(async_fn_in_trait)] |
| 3 | #![doc = include_str!("../README.md")] | 16 | #![doc = include_str!("../README.md")] |
| @@ -37,6 +50,7 @@ pub use crate::sub::ble::hci; | |||
| 37 | 50 | ||
| 38 | type PacketHeader = LinkedListNode; | 51 | type PacketHeader = LinkedListNode; |
| 39 | 52 | ||
| 53 | /// Transport Layer for the Mailbox interface | ||
| 40 | pub struct TlMbox<'d> { | 54 | pub struct TlMbox<'d> { |
| 41 | _ipcc: PeripheralRef<'d, IPCC>, | 55 | _ipcc: PeripheralRef<'d, IPCC>, |
| 42 | 56 | ||
| @@ -49,6 +63,34 @@ pub struct TlMbox<'d> { | |||
| 49 | } | 63 | } |
| 50 | 64 | ||
| 51 | impl<'d> TlMbox<'d> { | 65 | impl<'d> TlMbox<'d> { |
| 66 | /// Initialise the Transport Layer, and creates and returns a wrapper around it. | ||
| 67 | /// | ||
| 68 | /// This method performs the initialisation laid out in AN5289 annex 14.1. However, it differs | ||
| 69 | /// from the implementation documented in Figure 64, to avoid needing to reference any C | ||
| 70 | /// function pointers. | ||
| 71 | /// | ||
| 72 | /// Annex 14.1 lays out the following methods that should be called: | ||
| 73 | /// 1. tl_mbox.c/TL_Init, which initialises the reference table that is shared between CPU1 | ||
| 74 | /// and CPU2. | ||
| 75 | /// 2. shci_tl.c/shci_init(), which initialises the system transport layer, and in turn | ||
| 76 | /// calls tl_mbox.c/TL_SYS_Init, which initialises SYSTEM_EVT_QUEUE channel. | ||
| 77 | /// 3. tl_mbox.c/TL_MM_Init(), which initialises the channel used for sending memory | ||
| 78 | /// manager commands. | ||
| 79 | /// 4. tl_mbox.c/TL_Enable(), which enables the IPCC, and starts CPU2. | ||
| 80 | /// This implementation initialises all of the shared refernce tables and all IPCC channel that | ||
| 81 | /// would be initialised by this process. The developer should therefore treat this method as | ||
| 82 | /// completing all steps in Figure 64. | ||
| 83 | /// | ||
| 84 | /// Once this method has been called, no system commands may be sent until the CPU2 ready | ||
| 85 | /// signal is received, via [sys_subsystem.read]; this completes the procedure laid out in | ||
| 86 | /// Figure 65. | ||
| 87 | /// | ||
| 88 | /// If the `ble` feature is enabled, at this point, the user should call | ||
| 89 | /// [sys_subsystem.shci_c2_ble_init], before any commands are written to the | ||
| 90 | /// [TlMbox.ble_subsystem] ([sub::ble::Ble::new()] completes the process that would otherwise | ||
| 91 | /// be handled by `TL_BLE_Init`; see Figure 66). This completes the procedure laid out in | ||
| 92 | /// Figure 66. | ||
| 93 | // TODO: document what the user should do after calling init to use the mac_802_15_4 subsystem | ||
| 52 | pub fn init( | 94 | pub fn init( |
| 53 | ipcc: impl Peripheral<P = IPCC> + 'd, | 95 | ipcc: impl Peripheral<P = IPCC> + 'd, |
| 54 | _irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler> | 96 | _irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler> |
| @@ -57,6 +99,9 @@ impl<'d> TlMbox<'d> { | |||
| 57 | ) -> Self { | 99 | ) -> Self { |
| 58 | into_ref!(ipcc); | 100 | into_ref!(ipcc); |
| 59 | 101 | ||
| 102 | // this is an inlined version of TL_Init from the STM32WB firmware as requested by AN5289. | ||
| 103 | // HW_IPCC_Init is not called, and its purpose is (presumably?) covered by this | ||
| 104 | // implementation | ||
| 60 | unsafe { | 105 | unsafe { |
| 61 | TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable { | 106 | TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable { |
| 62 | device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(), | 107 | device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(), |
| @@ -140,6 +185,7 @@ impl<'d> TlMbox<'d> { | |||
| 140 | 185 | ||
| 141 | compiler_fence(Ordering::SeqCst); | 186 | compiler_fence(Ordering::SeqCst); |
| 142 | 187 | ||
| 188 | // this is equivalent to `HW_IPCC_Enable`, which is called by `TL_Enable` | ||
| 143 | Ipcc::enable(config); | 189 | Ipcc::enable(config); |
| 144 | 190 | ||
| 145 | Self { | 191 | Self { |
diff --git a/embassy-stm32-wpan/src/sub/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs index c5f2334f4..0f770d92c 100644 --- a/embassy-stm32-wpan/src/sub/ble.rs +++ b/embassy-stm32-wpan/src/sub/ble.rs | |||
| @@ -11,11 +11,39 @@ use crate::tables::{BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA | |||
| 11 | use crate::unsafe_linked_list::LinkedListNode; | 11 | use crate::unsafe_linked_list::LinkedListNode; |
| 12 | use crate::{channels, evt}; | 12 | use crate::{channels, evt}; |
| 13 | 13 | ||
| 14 | /// A guard that, once constructed, may be used to send BLE commands to CPU2. | ||
| 15 | /// | ||
| 16 | /// It is the responsibility of the caller to ensure that they have awaited an event via | ||
| 17 | /// [crate::sub::sys::Sys::read] before sending any of these commands, and to call | ||
| 18 | /// [crate::sub::sys::Sys::shci_c2_ble_init] and await the HCI_COMMAND_COMPLETE_EVENT before | ||
| 19 | /// sending any other commands. | ||
| 20 | /// | ||
| 21 | /// # Example | ||
| 22 | /// | ||
| 23 | /// ``` | ||
| 24 | /// # embassy_stm32::bind_interrupts!(struct Irqs{ | ||
| 25 | /// # IPCC_C1_RX => ReceiveInterruptHandler; | ||
| 26 | /// # IPCC_C1_TX => TransmitInterruptHandler; | ||
| 27 | /// # }); | ||
| 28 | /// # | ||
| 29 | /// # let p = embassy_stm32::init(embassy_stm32::Config::default()); | ||
| 30 | /// # let mut mbox = embassy_stm32_wpan::TlMbox::init(p.IPCC, Irqs, embassy_stm32::ipcc::Config::default()); | ||
| 31 | /// # | ||
| 32 | /// # let sys_event = mbox.sys_subsystem.read().await; | ||
| 33 | /// # let _command_status = mbox.sys_subsystem.shci_c2_ble_init(Default::default()); | ||
| 34 | /// # // BLE commands may now be sent | ||
| 35 | /// # | ||
| 36 | /// # mbox.ble_subsystem.reset().await; | ||
| 37 | /// # let _reset_response = mbox.ble_subsystem.read().await; | ||
| 38 | /// ``` | ||
| 14 | pub struct Ble { | 39 | pub struct Ble { |
| 15 | _private: (), | 40 | _private: (), |
| 16 | } | 41 | } |
| 17 | 42 | ||
| 18 | impl Ble { | 43 | impl Ble { |
| 44 | /// Constructs a guard that allows for BLE commands to be sent to CPU2. | ||
| 45 | /// | ||
| 46 | /// This takes the place of `TL_BLE_Init`, completing that step as laid out in AN5289, Fig 66. | ||
| 19 | pub(crate) fn new() -> Self { | 47 | pub(crate) fn new() -> Self { |
| 20 | unsafe { | 48 | unsafe { |
| 21 | LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); | 49 | LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); |
| @@ -30,6 +58,7 @@ impl Ble { | |||
| 30 | 58 | ||
| 31 | Self { _private: () } | 59 | Self { _private: () } |
| 32 | } | 60 | } |
| 61 | |||
| 33 | /// `HW_IPCC_BLE_EvtNot` | 62 | /// `HW_IPCC_BLE_EvtNot` |
| 34 | pub async fn tl_read(&self) -> EvtBox<Self> { | 63 | pub async fn tl_read(&self) -> EvtBox<Self> { |
| 35 | Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe { | 64 | Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe { |
diff --git a/embassy-stm32-wpan/src/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs index bd2ea3f74..cf6df58bf 100644 --- a/embassy-stm32-wpan/src/sub/sys.rs +++ b/embassy-stm32-wpan/src/sub/sys.rs | |||
| @@ -10,6 +10,7 @@ use crate::tables::{SysTable, WirelessFwInfoTable}; | |||
| 10 | use crate::unsafe_linked_list::LinkedListNode; | 10 | use crate::unsafe_linked_list::LinkedListNode; |
| 11 | use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE}; | 11 | use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE}; |
| 12 | 12 | ||
| 13 | /// A guard that, once constructed, allows for sys commands to be sent to CPU2. | ||
| 13 | pub struct Sys { | 14 | pub struct Sys { |
| 14 | _private: (), | 15 | _private: (), |
| 15 | } | 16 | } |
| @@ -86,12 +87,22 @@ impl Sys { | |||
| 86 | self.write_and_get_response(ShciOpcode::Mac802_15_4Init, &[]).await | 87 | self.write_and_get_response(ShciOpcode::Mac802_15_4Init, &[]).await |
| 87 | } | 88 | } |
| 88 | 89 | ||
| 90 | /// Send a request to CPU2 to initialise the BLE stack. | ||
| 91 | /// | ||
| 92 | /// This must be called before any BLE commands are sent via the BLE channel (according to | ||
| 93 | /// AN5289, Figures 65 and 66). It should only be called after CPU2 sends a system event, via | ||
| 94 | /// `HW_IPCC_SYS_EvtNot`, aka `IoBusCallBackUserEvt` (as detailed in Figure 65), aka | ||
| 95 | /// [crate::sub::ble::hci::host::uart::UartHci::read]. | ||
| 89 | #[cfg(feature = "ble")] | 96 | #[cfg(feature = "ble")] |
| 90 | pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> Result<SchiCommandStatus, ()> { | 97 | pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> Result<SchiCommandStatus, ()> { |
| 91 | self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await | 98 | self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await |
| 92 | } | 99 | } |
| 93 | 100 | ||
| 94 | /// `HW_IPCC_SYS_EvtNot` | 101 | /// `HW_IPCC_SYS_EvtNot` |
| 102 | /// | ||
| 103 | /// This method takes the place of the `HW_IPCC_SYS_EvtNot`/`SysUserEvtRx`/`APPE_SysUserEvtRx`, | ||
| 104 | /// as the embassy implementation avoids the need to call C public bindings, and instead | ||
| 105 | /// handles the event channels directly. | ||
| 95 | pub async fn read(&self) -> EvtBox<mm::MemoryManager> { | 106 | pub async fn read(&self) -> EvtBox<mm::MemoryManager> { |
| 96 | Ipcc::receive(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, || unsafe { | 107 | Ipcc::receive(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, || unsafe { |
| 97 | if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) { | 108 | if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) { |
diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs index f2c250527..fe6fc47a3 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/tables.rs | |||
| @@ -25,17 +25,17 @@ pub struct RssInfoTable { | |||
| 25 | 25 | ||
| 26 | /** | 26 | /** |
| 27 | * Version | 27 | * Version |
| 28 | * [0:3] = Build - 0: Untracked - 15:Released - x: Tracked version | 28 | * \[0:3\] = Build - 0: Untracked - 15:Released - x: Tracked version |
| 29 | * [4:7] = branch - 0: Mass Market - x: ... | 29 | * \[4:7\] = branch - 0: Mass Market - x: ... |
| 30 | * [8:15] = Subversion | 30 | * \[8:15\] = Subversion |
| 31 | * [16:23] = Version minor | 31 | * \[16:23\] = Version minor |
| 32 | * [24:31] = Version major | 32 | * \[24:31\] = Version major |
| 33 | * | 33 | * |
| 34 | * Memory Size | 34 | * Memory Size |
| 35 | * [0:7] = Flash ( Number of 4k sector) | 35 | * \[0:7\] = Flash ( Number of 4k sector) |
| 36 | * [8:15] = Reserved ( Shall be set to 0 - may be used as flash extension ) | 36 | * \[8:15\] = Reserved ( Shall be set to 0 - may be used as flash extension ) |
| 37 | * [16:23] = SRAM2b ( Number of 1k sector) | 37 | * \[16:23\] = SRAM2b ( Number of 1k sector) |
| 38 | * [24:31] = SRAM2a ( Number of 1k sector) | 38 | * \[24:31\] = SRAM2a ( Number of 1k sector) |
| 39 | */ | 39 | */ |
| 40 | #[derive(Debug, Copy, Clone)] | 40 | #[derive(Debug, Copy, Clone)] |
| 41 | #[repr(C, packed)] | 41 | #[repr(C, packed)] |
| @@ -89,12 +89,19 @@ pub struct DeviceInfoTable { | |||
| 89 | pub wireless_fw_info_table: WirelessFwInfoTable, | 89 | pub wireless_fw_info_table: WirelessFwInfoTable, |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | /// The bluetooth reference table, as defined in figure 67 of STM32WX AN5289. | ||
| 92 | #[derive(Debug)] | 93 | #[derive(Debug)] |
| 93 | #[repr(C)] | 94 | #[repr(C)] |
| 94 | pub struct BleTable { | 95 | pub struct BleTable { |
| 96 | /// A pointer to the buffer that is used for sending BLE commands. | ||
| 95 | pub pcmd_buffer: *mut CmdPacket, | 97 | pub pcmd_buffer: *mut CmdPacket, |
| 98 | /// A pointer to the buffer used for storing Command statuses. | ||
| 96 | pub pcs_buffer: *const u8, | 99 | pub pcs_buffer: *const u8, |
| 100 | /// A pointer to the event queue, over which IPCC BLE events are sent. This may be accessed via | ||
| 101 | /// [crate::sub::ble::Ble::tl_read]. | ||
| 97 | pub pevt_queue: *const u8, | 102 | pub pevt_queue: *const u8, |
| 103 | /// A pointer to the buffer that is used for sending HCI (Host-Controller Interface) ACL | ||
| 104 | /// (Asynchronous Connection-oriented Logical transport) commands (unused). | ||
| 98 | pub phci_acl_data_buffer: *mut AclDataPacket, | 105 | pub phci_acl_data_buffer: *mut AclDataPacket, |
| 99 | } | 106 | } |
| 100 | 107 | ||
| @@ -271,6 +278,6 @@ pub static mut BLE_SPARE_EVT_BUF: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_ | |||
| 271 | 278 | ||
| 272 | #[cfg(feature = "ble")] | 279 | #[cfg(feature = "ble")] |
| 273 | #[link_section = "MB_MEM2"] | 280 | #[link_section = "MB_MEM2"] |
| 274 | // fuck these "magic" numbers from ST ---v---v | 281 | // fuck these "magic" numbers from ST ---v---v |
| 275 | pub static mut HCI_ACL_DATA_BUFFER: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]>> = | 282 | pub static mut HCI_ACL_DATA_BUFFER: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]>> = |
| 276 | Aligned(MaybeUninit::uninit()); | 283 | Aligned(MaybeUninit::uninit()); |
diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs index 1cc50e134..041dc0cf5 100644 --- a/examples/stm32wb/src/bin/gatt_server.rs +++ b/examples/stm32wb/src/bin/gatt_server.rs | |||
| @@ -151,11 +151,6 @@ async fn main(_spawner: Spawner) { | |||
| 151 | let response = mbox.ble_subsystem.read().await; | 151 | let response = mbox.ble_subsystem.read().await; |
| 152 | defmt::debug!("{}", response); | 152 | defmt::debug!("{}", response); |
| 153 | 153 | ||
| 154 | info!("set scan response data..."); | ||
| 155 | mbox.ble_subsystem.le_set_scan_response_data(b"TXTX").await.unwrap(); | ||
| 156 | let response = mbox.ble_subsystem.read().await; | ||
| 157 | defmt::debug!("{}", response); | ||
| 158 | |||
| 159 | defmt::info!("initializing services and characteristics..."); | 154 | defmt::info!("initializing services and characteristics..."); |
| 160 | let mut ble_context = init_gatt_services(&mut mbox.ble_subsystem).await.unwrap(); | 155 | let mut ble_context = init_gatt_services(&mut mbox.ble_subsystem).await.unwrap(); |
| 161 | defmt::info!("{}", ble_context); | 156 | defmt::info!("{}", ble_context); |
