diff --git a/examples/ble_l2cap_server.rs b/examples/ble_l2cap_server.rs index 40a99fb..a2c9bc4 100644 --- a/examples/ble_l2cap_server.rs +++ b/examples/ble_l2cap_server.rs @@ -16,14 +16,11 @@ fn main() { .unwrap(); ble_advertising.lock().start().unwrap(); - L2capServer::create(0x1001, 512, |data| { - ::log::info!("Data received(0x1001): {:X?}", data.sdu_rx()); - }) - .unwrap(); - L2capServer::create(0x1002, 512, |data| { - ::log::info!("Data received(0x1002): {:X?}", data.sdu_rx()); - }) - .unwrap(); + let l2cap1 = L2capServer::create(0x1001, 512).unwrap(); + let l2cap2 = L2capServer::create(0x1002, 512).unwrap(); + + block_on(async { + }); loop { esp_idf_hal::delay::FreeRtos::delay_ms(1000); diff --git a/src/l2cap/l2cap_client.rs b/src/l2cap/l2cap_client.rs index b5f4001..ac5725b 100644 --- a/src/l2cap/l2cap_client.rs +++ b/src/l2cap/l2cap_client.rs @@ -2,16 +2,9 @@ use alloc::boxed::Box; use core::borrow::BorrowMut; use esp_idf_hal::task::block_on; -#[cfg(not(esp_idf_soc_esp_nimble_controller))] -use esp_idf_sys::os_mbuf_free; -#[cfg(esp_idf_soc_esp_nimble_controller)] -use esp_idf_sys::r_os_mbuf_free as os_mbuf_free; - use super::{L2cap, ReceivedData}; use crate::{ - ble, - utilities::{os_mbuf_append, voidp_to_ref}, - BLEClient, BLEError, Signal, + ble, utilities::voidp_to_ref, BLEClient, BLEError, Channel, Signal }; #[allow(clippy::type_complexity)] @@ -19,7 +12,7 @@ pub struct L2capClient { l2cap: L2cap, coc_chan: *mut esp_idf_sys::ble_l2cap_chan, signal: Signal, - on_data_received: Option>, + channel: Channel, } impl L2capClient { @@ -28,7 +21,7 @@ impl L2capClient { l2cap: Default::default(), coc_chan: core::ptr::null_mut(), signal: Signal::new(), - on_data_received: None, + channel: Channel::new(), }); ret.l2cap.init(mtu, 3)?; @@ -60,39 +53,12 @@ impl L2capClient { Ok(()) } - pub fn send(&mut self, data: &[u8]) -> Result<(), BLEError> { - let mtu = L2cap::get_chan_info(self.coc_chan).peer_l2cap_mtu as usize; - let mut data = data; - - while !data.is_empty() { - let sdu_rx = self.l2cap.sdu_rx(); - let (data0, data1) = data.split_at(if data.len() < mtu { data.len() } else { mtu }); - - let rc = os_mbuf_append(sdu_rx, data0); - assert_eq!(rc, 0); - - loop { - let rc = unsafe { esp_idf_sys::ble_l2cap_send(self.coc_chan, sdu_rx) }; - match rc as _ { - 0 | esp_idf_sys::BLE_HS_ESTALLED => break, - esp_idf_sys::BLE_HS_EBUSY => {} - rc => return BLEError::convert(rc), - } - unsafe { esp_idf_sys::vPortYield() }; - } - - data = data1; - } - - Ok(()) + pub fn tx(&mut self, data: &[u8]) -> Result<(), BLEError> { + self.l2cap.tx(self.coc_chan, data) } - pub fn on_data_received( - &mut self, - callback: impl FnMut(ReceivedData) + Send + Sync + 'static, - ) -> &mut Self { - self.on_data_received = Some(Box::new(callback)); - self + pub async fn rx(&mut self) -> ReceivedData { + self.channel.receive().await } pub(crate) extern "C" fn blecent_l2cap_coc_event_cb( @@ -126,11 +92,7 @@ impl L2capClient { esp_idf_sys::BLE_L2CAP_EVENT_COC_DATA_RECEIVED => { let receive = unsafe { event.__bindgen_anon_1.receive }; if !receive.sdu_rx.is_null() { - if let Some(callback) = &mut client.on_data_received { - callback(ReceivedData::from_raw(receive)); - } else { - unsafe { os_mbuf_free(receive.sdu_rx) }; - } + let _ = client.channel.try_send(ReceivedData::from_raw(receive)); } client.l2cap.ble_l2cap_recv_ready(receive.chan); 0 diff --git a/src/l2cap/l2cap_core.rs b/src/l2cap/l2cap_core.rs new file mode 100644 index 0000000..b8a13cb --- /dev/null +++ b/src/l2cap/l2cap_core.rs @@ -0,0 +1,93 @@ +use crate::{ble, utilities::os_mbuf_append, BLEError}; +use alloc::vec::Vec; + +#[derive(Default)] +pub struct L2cap { + mempool: esp_idf_sys::os_mempool, + mbuf_pool: esp_idf_sys::os_mbuf_pool, + coc_memory: Vec, +} + +impl L2cap { + pub fn init(&mut self, mtu: u16, coc_buf_count: u16) -> Result<(), BLEError> { + self + .coc_memory + .reserve_exact(os_mempool_size(coc_buf_count as _, mtu as _)); + + unsafe { + ble!(super::os_mempool_init( + &mut self.mempool, + coc_buf_count, + mtu as _, + self.coc_memory.as_mut_ptr() as _, + c"coc_sdu_pool".as_ptr() + ))?; + + ble!(super::os_mbuf_pool_init( + &mut self.mbuf_pool as _, + &mut self.mempool as _, + mtu, + coc_buf_count + ))?; + } + + Ok(()) + } + + pub fn tx(&mut self, chan: *mut esp_idf_sys::ble_l2cap_chan, data: &[u8]) -> Result<(), BLEError> { + let mtu = L2cap::get_chan_info(chan).peer_l2cap_mtu as usize; + let mut data = data; + + while !data.is_empty() { + let sdu_rx = self.sdu_rx(); + let (data0, data1) = data.split_at(if data.len() < mtu { data.len() } else { mtu }); + + let rc = os_mbuf_append(sdu_rx, data0); + assert_eq!(rc, 0); + + loop { + let rc = unsafe { esp_idf_sys::ble_l2cap_send(chan, sdu_rx) }; + match rc as _ { + 0 | esp_idf_sys::BLE_HS_ESTALLED => break, + esp_idf_sys::BLE_HS_EBUSY => {} + rc => return BLEError::convert(rc), + } + unsafe { esp_idf_sys::vPortYield() }; + } + + data = data1; + } + + Ok(()) + } + + pub fn sdu_rx(&mut self) -> *mut esp_idf_sys::os_mbuf { + loop { + let ret = unsafe { super::os_mbuf_get_pkthdr(&mut self.mbuf_pool, 0) }; + if !ret.is_null() { + return ret; + } + esp_idf_hal::delay::FreeRtos::delay_ms(10); + } + } + + pub(crate) fn ble_l2cap_recv_ready(&mut self, chan: *mut esp_idf_sys::ble_l2cap_chan) -> i32 { + let sdu_rx = self.sdu_rx(); + unsafe { esp_idf_sys::ble_l2cap_recv_ready(chan, sdu_rx) } + } + + pub(crate) fn get_chan_info( + chan: *mut esp_idf_sys::ble_l2cap_chan, + ) -> esp_idf_sys::ble_l2cap_chan_info { + let mut chan_info = esp_idf_sys::ble_l2cap_chan_info::default(); + let rc = unsafe { esp_idf_sys::ble_l2cap_get_chan_info(chan, &mut chan_info as _) }; + assert_eq!(rc, 0); + chan_info + } +} + +#[inline] +const fn os_mempool_size(n: usize, blksize: usize) -> usize { + let size = core::mem::size_of::(); + blksize.div_ceil(size) * n +} \ No newline at end of file diff --git a/src/l2cap/l2cap_server.rs b/src/l2cap/l2cap_server.rs index 54d2a55..c7c255b 100644 --- a/src/l2cap/l2cap_server.rs +++ b/src/l2cap/l2cap_server.rs @@ -12,6 +12,7 @@ static SERVER_LIST: Mutex> = Mutex::new(heapless:: #[allow(clippy::type_complexity)] pub struct L2capServer { l2cap: L2cap, + coc_chan: *mut esp_idf_sys::ble_l2cap_chan, peer_sdu_size: u16, channel: Channel, } @@ -20,11 +21,12 @@ impl L2capServer { pub fn create( psm: u16, mtu: u16, - ) -> Result<(), BLEError> { + ) -> Result<&'_ mut L2capServer, BLEError> { let mut list = SERVER_LIST.lock(); list .push(L2capServer { l2cap: Default::default(), + coc_chan: core::ptr::null_mut(), peer_sdu_size: 0, channel: Channel::new(), }) @@ -41,7 +43,11 @@ impl L2capServer { server as *mut Self as _, ))?; } - Ok(()) + Ok(list.last_mut().unwrap()) + } + + pub fn tx(&mut self, data: &[u8]) -> Result<(), BLEError> { + self.l2cap.tx(self.coc_chan, data) } pub async fn rx(&mut self) -> ReceivedData { @@ -63,6 +69,13 @@ impl L2capServer { return 0; } + server.coc_chan = connect.chan; + 0 + } + esp_idf_sys::BLE_L2CAP_EVENT_COC_DISCONNECTED => { + let disconnect = unsafe { event.__bindgen_anon_1.disconnect }; + ::log::debug!("LE CoC disconnected: {:?}", disconnect.chan); + server.coc_chan = core::ptr::null_mut(); 0 } esp_idf_sys::BLE_L2CAP_EVENT_COC_ACCEPT => { diff --git a/src/l2cap/mod.rs b/src/l2cap/mod.rs index ef9752a..04bc815 100644 --- a/src/l2cap/mod.rs +++ b/src/l2cap/mod.rs @@ -1,9 +1,20 @@ + +#[cfg(not(esp_idf_soc_esp_nimble_controller))] +use esp_idf_sys::{os_mbuf_free, os_mbuf_get_pkthdr, os_mbuf_pool_init, os_mempool_init}; +#[cfg(esp_idf_soc_esp_nimble_controller)] +use esp_idf_sys::{ + r_os_mbuf_free as os_mbuf_free, r_os_mbuf_get_pkthdr as os_mbuf_get_pkthdr, + r_os_mbuf_pool_init as os_mbuf_pool_init, r_os_mempool_init as os_mempool_init, +}; + mod l2cap_client; pub use l2cap_client::L2capClient; mod l2cap_server; pub use l2cap_server::L2capServer; +mod l2cap_core; +use l2cap_core::L2cap; + mod utilities; -pub(crate) use utilities::L2cap; pub use utilities::ReceivedData; diff --git a/src/l2cap/utilities.rs b/src/l2cap/utilities.rs index acdbefd..52a3e9d 100644 --- a/src/l2cap/utilities.rs +++ b/src/l2cap/utilities.rs @@ -1,77 +1,4 @@ -use crate::{ble, utilities::os_mbuf_into_slice, BLEError}; -use alloc::vec::Vec; - -#[cfg(not(esp_idf_soc_esp_nimble_controller))] -use esp_idf_sys::{os_mbuf_free, os_mbuf_get_pkthdr, os_mbuf_pool_init, os_mempool_init}; -#[cfg(esp_idf_soc_esp_nimble_controller)] -use esp_idf_sys::{ - r_os_mbuf_free as os_mbuf_free, r_os_mbuf_get_pkthdr as os_mbuf_get_pkthdr, - r_os_mbuf_pool_init as os_mbuf_pool_init, r_os_mempool_init as os_mempool_init, -}; - -#[derive(Default)] -pub struct L2cap { - mempool: esp_idf_sys::os_mempool, - mbuf_pool: esp_idf_sys::os_mbuf_pool, - coc_memory: Vec, -} - -impl L2cap { - pub fn init(&mut self, mtu: u16, coc_buf_count: u16) -> Result<(), BLEError> { - self - .coc_memory - .reserve_exact(os_mempool_size(coc_buf_count as _, mtu as _)); - - unsafe { - ble!(os_mempool_init( - &mut self.mempool, - coc_buf_count, - mtu as _, - self.coc_memory.as_mut_ptr() as _, - c"coc_sdu_pool".as_ptr() - ))?; - - ble!(os_mbuf_pool_init( - &mut self.mbuf_pool as _, - &mut self.mempool as _, - mtu, - coc_buf_count - ))?; - } - - Ok(()) - } - - pub fn sdu_rx(&mut self) -> *mut esp_idf_sys::os_mbuf { - loop { - let ret = unsafe { os_mbuf_get_pkthdr(&mut self.mbuf_pool, 0) }; - if !ret.is_null() { - return ret; - } - esp_idf_hal::delay::FreeRtos::delay_ms(10); - } - } - - pub(crate) fn ble_l2cap_recv_ready(&mut self, chan: *mut esp_idf_sys::ble_l2cap_chan) -> i32 { - let sdu_rx = self.sdu_rx(); - unsafe { esp_idf_sys::ble_l2cap_recv_ready(chan, sdu_rx) } - } - - pub(crate) fn get_chan_info( - chan: *mut esp_idf_sys::ble_l2cap_chan, - ) -> esp_idf_sys::ble_l2cap_chan_info { - let mut chan_info = esp_idf_sys::ble_l2cap_chan_info::default(); - let rc = unsafe { esp_idf_sys::ble_l2cap_get_chan_info(chan, &mut chan_info as _) }; - assert_eq!(rc, 0); - chan_info - } -} - -#[inline] -const fn os_mempool_size(n: usize, blksize: usize) -> usize { - let size = core::mem::size_of::(); - blksize.div_ceil(size) * n -} +use crate::utilities::os_mbuf_into_slice; pub struct ReceivedData(esp_idf_sys::ble_l2cap_event__bindgen_ty_1__bindgen_ty_4); @@ -94,6 +21,6 @@ impl ReceivedData { impl Drop for ReceivedData { fn drop(&mut self) { - unsafe { os_mbuf_free(self.0.sdu_rx) }; + unsafe { super::os_mbuf_free(self.0.sdu_rx) }; } }