diff --git a/examples/nrf-sdc/src/bin/ble_bas_peripheral.rs b/examples/nrf-sdc/src/bin/ble_bas_peripheral.rs index c9303320..4149815b 100644 --- a/examples/nrf-sdc/src/bin/ble_bas_peripheral.rs +++ b/examples/nrf-sdc/src/bin/ble_bas_peripheral.rs @@ -112,7 +112,7 @@ async fn main(spawner: Spawner) { StaticCell::new(); let host_resources = HOST_RESOURCES.init(HostResources::new(PacketQos::None)); - let mut adapter: Adapter<'_, NoopRawMutex, _, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX> = + let mut adapter: Adapter<'_, NoopRawMutex, _, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, L2CAP_MTU> = Adapter::new(sdc, host_resources); adapter.set_random_address(my_addr()); diff --git a/examples/nrf-sdc/src/bin/ble_l2cap_central.rs b/examples/nrf-sdc/src/bin/ble_l2cap_central.rs index b57fc0bc..4d89f143 100644 --- a/examples/nrf-sdc/src/bin/ble_l2cap_central.rs +++ b/examples/nrf-sdc/src/bin/ble_l2cap_central.rs @@ -120,7 +120,7 @@ async fn main(spawner: Spawner) { StaticCell::new(); let host_resources = HOST_RESOURCES.init(HostResources::new(PacketQos::Guaranteed(4))); - let mut adapter: Adapter<'_, NoopRawMutex, _, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX> = + let mut adapter: Adapter<'_, NoopRawMutex, _, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, L2CAP_MTU> = Adapter::new(sdc, host_resources); adapter.set_random_address(my_addr()); @@ -141,17 +141,17 @@ async fn main(spawner: Spawner) { let conn = unwrap!(adapter.connect(&config).await); info!("Connected, creating l2cap channel"); const PAYLOAD_LEN: usize = 27; - let mut ch1: L2capChannel<'_, '_, _, PAYLOAD_LEN> = + let mut ch1 = unwrap!(L2capChannel::create(&adapter, &conn, 0x2349, PAYLOAD_LEN as u16, Default::default()).await); info!("New l2cap channel created, sending some data!"); for i in 0..10 { let tx = [i; PAYLOAD_LEN]; - unwrap!(ch1.send(&tx).await); + unwrap!(ch1.send(&adapter, &tx).await); } info!("Sent data, waiting for them to be sent back"); let mut rx = [0; PAYLOAD_LEN]; for i in 0..10 { - let len = unwrap!(ch1.receive(&mut rx).await); + let len = unwrap!(ch1.receive(&adapter, &mut rx).await); assert_eq!(len, rx.len()); assert_eq!(rx, [i; PAYLOAD_LEN]); } diff --git a/examples/nrf-sdc/src/bin/ble_l2cap_peripheral.rs b/examples/nrf-sdc/src/bin/ble_l2cap_peripheral.rs index a8ca0e83..958f3962 100644 --- a/examples/nrf-sdc/src/bin/ble_l2cap_peripheral.rs +++ b/examples/nrf-sdc/src/bin/ble_l2cap_peripheral.rs @@ -119,7 +119,7 @@ async fn main(spawner: Spawner) { StaticCell::new(); let host_resources = HOST_RESOURCES.init(HostResources::new(PacketQos::Guaranteed(4))); - let mut adapter: Adapter<'_, NoopRawMutex, _, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX> = + let mut adapter: Adapter<'_, NoopRawMutex, _, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, L2CAP_MTU> = Adapter::new(sdc, host_resources); adapter.set_random_address(my_addr()); let mut adv_data = [0; 31]; @@ -151,7 +151,7 @@ async fn main(spawner: Spawner) { info!("Connection established"); - let mut ch1: L2capChannel<'_, '_, _, PAYLOAD_LEN> = + let mut ch1 = unwrap!(L2capChannel::accept(&adapter, &conn, &[0x2349], PAYLOAD_LEN as u16, Default::default()).await); info!("L2CAP channel accepted"); @@ -160,7 +160,7 @@ async fn main(spawner: Spawner) { const PAYLOAD_LEN: usize = 27; let mut rx = [0; PAYLOAD_LEN]; for i in 0..10 { - let len = unwrap!(ch1.receive(&mut rx).await); + let len = unwrap!(ch1.receive(&adapter, &mut rx).await); assert_eq!(len, rx.len()); assert_eq!(rx, [i; PAYLOAD_LEN]); } @@ -169,7 +169,7 @@ async fn main(spawner: Spawner) { Timer::after(Duration::from_secs(1)).await; for i in 0..10 { let tx = [i; PAYLOAD_LEN]; - unwrap!(ch1.send(&tx).await); + unwrap!(ch1.send(&adapter, &tx).await); } info!("L2CAP data echoed"); diff --git a/examples/serial-hci/src/main.rs b/examples/serial-hci/src/main.rs index aaf99acb..8b83e0a5 100644 --- a/examples/serial-hci/src/main.rs +++ b/examples/serial-hci/src/main.rs @@ -61,7 +61,7 @@ async fn main() { static HOST_RESOURCES: StaticCell> = StaticCell::new(); let host_resources = HOST_RESOURCES.init(HostResources::new(PacketQos::None)); - let adapter: Adapter<'_, NoopRawMutex, _, 2, 4, 1, 1> = Adapter::new(controller, host_resources); + let adapter: Adapter<'_, NoopRawMutex, _, 2, 4, 27, 1, 1> = Adapter::new(controller, host_resources); let mut table: AttributeTable<'_, NoopRawMutex, 10> = AttributeTable::new(); diff --git a/host/src/adapter.rs b/host/src/adapter.rs index 14e82982..43497ce3 100644 --- a/host/src/adapter.rs +++ b/host/src/adapter.rs @@ -65,6 +65,7 @@ pub struct Adapter< T, const CONNS: usize, const CHANNELS: usize, + const L2CAP_MTU: usize, const L2CAP_TXQ: usize = 1, const L2CAP_RXQ: usize = 1, > where @@ -74,7 +75,7 @@ pub struct Adapter< pub(crate) controller: T, pub(crate) connections: ConnectionManager, pub(crate) reassembly: PacketReassembly<'d, CONNS>, - pub(crate) channels: ChannelManager<'d, M, CHANNELS, L2CAP_TXQ, L2CAP_RXQ>, + pub(crate) channels: ChannelManager<'d, M, CHANNELS, L2CAP_MTU, L2CAP_TXQ, L2CAP_RXQ>, pub(crate) att_inbound: Channel), L2CAP_RXQ>, pub(crate) pool: &'d dyn DynamicPacketPool<'d>, pub(crate) permits: LocalSemaphore, @@ -82,8 +83,16 @@ pub struct Adapter< pub(crate) scanner: Channel, 1>, } -impl<'d, M, T, const CONNS: usize, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP_RXQ: usize> - Adapter<'d, M, T, CONNS, CHANNELS, L2CAP_TXQ, L2CAP_RXQ> +impl< + 'd, + M, + T, + const CONNS: usize, + const CHANNELS: usize, + const L2CAP_MTU: usize, + const L2CAP_TXQ: usize, + const L2CAP_RXQ: usize, + > Adapter<'d, M, T, CONNS, CHANNELS, L2CAP_MTU, L2CAP_TXQ, L2CAP_RXQ> where M: RawMutex, T: Controller, @@ -94,7 +103,7 @@ where /// /// The adapter requires a HCI driver (a particular HCI-compatible controller implementing the required traits), and /// a reference to resources that are created outside the adapter but which the adapter is the only accessor of. - pub fn new( + pub fn new( controller: T, host_resources: &'d mut HostResources, ) -> Self { @@ -139,6 +148,22 @@ where Ok(ret) } + pub fn try_command(&self, cmd: C) -> Result> + where + C: SyncCmd, + T: ControllerCmdSync, + { + let fut = cmd.exec(&self.controller); + match embassy_futures::poll_once(fut) { + Poll::Ready(result) => match result { + Ok(r) => Ok(r), + Err(CmdError::Io(e)) => Err(AdapterError::Controller(e)), + Err(CmdError::Hci(e)) => Err(e.into()), + }, + Poll::Pending => Err(Error::Busy.into()), + } + } + pub async fn async_command(&self, cmd: C) -> Result<(), AdapterError> where C: AsyncCmd, @@ -193,8 +218,8 @@ where phy_params, )) .await?; - let info = self.connections.accept(config.scan_config.filter_accept_list).await; - Ok(Connection { info }) + let handle = self.connections.accept(config.scan_config.filter_accept_list).await; + Ok(Connection::new(handle)) } else { self.async_command(LeCreateConn::new( config.scan_config.interval.into(), @@ -211,8 +236,8 @@ where config.connect_params.event_length.into(), )) .await?; - let info = self.connections.accept(config.scan_config.filter_accept_list).await; - Ok(Connection { info }) + let handle = self.connections.accept(config.scan_config.filter_accept_list).await; + Ok(Connection::new(handle)) } } @@ -396,9 +421,9 @@ where } self.command(LeSetAdvEnable::new(true)).await?; - let conn = Connection::accept(self).await; + let handle = self.connections.accept(&[]).await; self.command(LeSetAdvEnable::new(false)).await?; - Ok(conn) + Ok(Connection::new(handle)) } /// Starts sending BLE advertisements according to the provided config. @@ -481,9 +506,9 @@ where } self.command(LeSetExtAdvEnable::new(true, &[params.set])).await?; - let conn = Connection::accept(self).await; + let handle = self.connections.accept(&[]).await; self.command(LeSetExtAdvEnable::new(false, &[])).await?; - Ok(conn) + Ok(Connection::new(handle)) } /// Creates a GATT server capable of processing the GATT protocol using the provided table of attributes. @@ -658,6 +683,7 @@ where pin_mut!(init_fut); loop { + // info!("[run] permits: {}", self.permits.permits()); // Task handling receiving data from the controller. let rx_fut = async { let mut rx = [0u8; MAX_HCI_PACKET_LEN]; @@ -672,7 +698,6 @@ where Event::Le(event) => match event { LeEvent::LeConnectionComplete(e) => match e.status.to_result() { Ok(_) => { - info!("Connection complete {:?}: {:?}", e.handle, e.peer_addr); if let Err(err) = self.connections.connect( e.handle, ConnectionInfo { @@ -726,7 +751,7 @@ where let _ = self.channels.disconnected_connection(e.handle); } Event::NumberOfCompletedPackets(c) => { - // trace!("Confirmed {} packets sent", c.completed_packets.len()); + // info!("Confirmed {} packets sent", c.completed_packets.len()); self.permits.release(c.completed_packets.len()); } Event::Vendor(vendor) => { @@ -783,6 +808,7 @@ impl<'d, T: Controller> Clone for HciController<'d, T> { impl<'d, T: Controller> HciController<'d, T> { pub(crate) fn try_send(&self, handle: ConnHandle, pdu: &[u8]) -> Result<(), AdapterError> { + // info!("[try_send] permits: {}", self.permits.permits()); let mut permit = self .permits .try_acquire(1) @@ -800,6 +826,7 @@ impl<'d, T: Controller> HciController<'d, T> { if result.is_ok() { permit.disarm(); } + result.map_err(AdapterError::Controller) } Poll::Pending => Err(Error::Busy.into()), @@ -807,6 +834,7 @@ impl<'d, T: Controller> HciController<'d, T> { } pub(crate) async fn send(&self, handle: ConnHandle, pdu: &[u8]) -> Result<(), AdapterError> { + // info!("[send] permits: {}", self.permits.permits()); self.permits.acquire(1).await.disarm(); let acl = AclPacket::new( handle, @@ -824,7 +852,7 @@ impl<'d, T: Controller> HciController<'d, T> { pub(crate) async fn signal( &self, handle: ConnHandle, - response: L2capLeSignal, + response: &L2capLeSignal, ) -> Result<(), AdapterError> { // TODO: Refactor signal to avoid encode/decode // info!("[{}] sending signal: {:?}", handle, response); @@ -832,7 +860,7 @@ impl<'d, T: Controller> HciController<'d, T> { let mut w = WriteCursor::new(&mut tx); let (mut header, mut body) = w.split(4)?; - body.write(response)?; + body.write_ref(response)?; // TODO: Move into l2cap packet type header.write(body.len() as u16)?; diff --git a/host/src/channel_manager.rs b/host/src/channel_manager.rs index 88a08d6c..4928978b 100644 --- a/host/src/channel_manager.rs +++ b/host/src/channel_manager.rs @@ -7,12 +7,13 @@ use core::{ use bt_hci::{controller::Controller, param::ConnHandle}; use embassy_sync::{ blocking_mutex::{raw::RawMutex, Mutex}, - channel::{Channel, DynamicReceiver}, + channel::Channel, waitqueue::WakerRegistration, }; use crate::{ adapter::HciController, + cursor::{ReadCursor, WriteCursor}, l2cap::L2capHeader, packet_pool::{AllocId, DynamicPacketPool, Packet}, pdu::Pdu, @@ -33,22 +34,27 @@ struct State { } /// Channel manager for L2CAP channels used directly by clients. -pub struct ChannelManager<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP_RXQ: usize> { +pub struct ChannelManager< + 'd, + M: RawMutex, + const CHANNELS: usize, + const L2CAP_MTU: usize, + const L2CAP_TXQ: usize, + const L2CAP_RXQ: usize, +> { pool: &'d dyn DynamicPacketPool<'d>, state: Mutex>>, inbound: [Channel>, L2CAP_RXQ>; CHANNELS], - //outbound: [Channel, L2CAP_TXQ>; CHANNELS], } -pub trait DynamicChannelManager<'d> { - fn poll_request_to_send(&self, cid: u16, credits: usize, cx: Option<&mut Context<'_>>) -> Poll>; - fn flow_control(&self, cid: u16) -> Result, Error>; - fn confirm_disconnected(&self, cid: u16) -> Result<(), Error>; - fn disconnect(&self, cid: u16) -> Result<(), Error>; -} - -impl<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP_RXQ: usize> - ChannelManager<'d, M, CHANNELS, L2CAP_TXQ, L2CAP_RXQ> +impl< + 'd, + M: RawMutex, + const CHANNELS: usize, + const L2CAP_MTU: usize, + const L2CAP_TXQ: usize, + const L2CAP_RXQ: usize, + > ChannelManager<'d, M, CHANNELS, L2CAP_MTU, L2CAP_TXQ, L2CAP_RXQ> { const TX_CHANNEL: Channel, L2CAP_TXQ> = Channel::new(); const RX_CHANNEL: Channel>, L2CAP_RXQ> = Channel::new(); @@ -81,7 +87,7 @@ impl<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP }) } - fn disconnect(&self, cid: u16) -> Result<(), Error> { + pub(crate) fn disconnect(&self, cid: u16) -> Result<(), Error> { let idx = self.state.lock(|state| { let mut state = state.borrow_mut(); for (idx, storage) in state.channels.iter_mut().enumerate() { @@ -273,7 +279,7 @@ impl<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP mut mtu: u16, credit_flow: CreditFlowPolicy, controller: &HciController<'_, T>, - ) -> Result<(ConnectedState, DynamicReceiver<'_, Option>>), AdapterError> { + ) -> Result> { let mut req_id = 0; let (idx, state) = poll_fn(|cx| { self.poll_accept(conn, psm, cx, |idx, req| { @@ -308,14 +314,14 @@ impl<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP }), ); - controller.signal(conn, response).await?; + controller.signal(conn, &response).await?; // Send initial credits let next_req_id = self.next_request_id(); controller .signal( conn, - L2capLeSignal::new( + &L2capLeSignal::new( next_req_id, L2capLeSignalData::LeCreditFlowInd(LeCreditFlowInd { cid: state.cid, @@ -325,7 +331,7 @@ impl<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP ) .await?; - Ok((state, self.inbound[idx].receiver().into())) + Ok(state.cid) } pub(crate) async fn create( @@ -335,7 +341,7 @@ impl<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP mtu: u16, credit_flow: CreditFlowPolicy, controller: &HciController<'_, T>, - ) -> Result<(ConnectedState, DynamicReceiver<'_, Option>>), AdapterError> { + ) -> Result> { let req_id = self.next_request_id(); let mut credits = 0; let mut cid: u16 = 0; @@ -366,10 +372,10 @@ impl<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP }), ); //info!("Signal packet to remote: {:?}", command); - controller.signal(conn, command).await?; + controller.signal(conn, &command).await?; // info!("Sent signal packet to remote, awaiting response"); - let (idx, state) = poll_fn(|cx| { + let (idx, cid) = poll_fn(|cx| { self.state.lock(|state| { let mut state = state.borrow_mut(); for (idx, storage) in state.channels.iter_mut().enumerate() { @@ -378,7 +384,7 @@ impl<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP return Poll::Ready(Err(Error::Disconnected)); } ChannelState::Connected(req) if req.conn == conn && req.cid == cid => { - return Poll::Ready(Ok((idx, req.clone()))); + return Poll::Ready(Ok((idx, req.cid))); } _ => {} } @@ -396,21 +402,15 @@ impl<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP controller .signal( conn, - L2capLeSignal::new( + &L2capLeSignal::new( next_req_id, - L2capLeSignalData::LeCreditFlowInd(LeCreditFlowInd { - cid: state.cid, - credits, - }), + L2capLeSignalData::LeCreditFlowInd(LeCreditFlowInd { cid, credits }), ), ) .await?; // info!("Done!"); - - let rx = self.inbound[idx].receiver().into(); - - Ok((state, rx)) + Ok(cid) } pub async fn dispatch(&self, header: L2capHeader, packet: Packet<'d>) -> Result<(), Error> { @@ -506,41 +506,183 @@ impl<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP } } } -} -impl<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP_RXQ: usize> DynamicChannelManager<'d> - for ChannelManager<'d, M, CHANNELS, L2CAP_TXQ, L2CAP_RXQ> -{ - fn flow_control(&self, cid: u16) -> Result, Error> { - let next_req_id = self.next_request_id(); - let ret = self.state.lock(|state| { + fn with_connected_channel R, R>( + &self, + cid: u16, + f: F, + ) -> Result { + self.state.lock(|state| { + let mut state = state.borrow_mut(); + for (idx, chan) in state.channels.iter_mut().enumerate() { + match chan { + ChannelState::Connected(state) if state.cid == cid => { + return Ok(f(idx, state)); + } + _ => {} + } + } + Err(Error::NotFound) + }) + } + + async fn receive_pdu(&self, cid: u16, idx: usize) -> Result, Error> { + match self.inbound[idx].receive().await { + Some(pdu) => Ok(pdu), + None => { + self.confirm_disconnected(cid)?; + Err(Error::ChannelClosed) + } + } + } + + pub(crate) async fn receive( + &self, + cid: u16, + buf: &mut [u8], + hci: &HciController<'_, T>, + ) -> Result> { + let idx = self.with_connected_channel(cid, |idx, _state| idx)?; + let mut n_received = 1; + let packet = self.receive_pdu(cid, idx).await?; + let len = packet.len; + + let mut r = ReadCursor::new(packet.as_ref()); + let remaining: u16 = r.read()?; + // info!("Total expected: {}", remaining); + + let data = r.remaining(); + let to_copy = data.len().min(buf.len()); + buf[..to_copy].copy_from_slice(&data[..to_copy]); + let mut pos = to_copy; + + // info!("Received {} bytes so far", pos); + + let mut remaining = remaining as usize - data.len(); + + drop(packet); + self.flow_control(cid, hci).await?; + //info!( + // "Total size of PDU is {}, read buffer size is {} remaining; {}", + // len, + // buf.len(), + // remaining + //); + // We have some k-frames to reassemble + while remaining > 0 { + let packet = self.receive_pdu(cid, idx).await?; + n_received += 1; + let to_copy = packet.len.min(buf.len() - pos); + if to_copy > 0 { + buf[pos..pos + to_copy].copy_from_slice(&packet.as_ref()[..to_copy]); + pos += to_copy; + } + remaining -= packet.len; + drop(packet); + self.flow_control(cid, hci).await?; + } + + // info!("Total reserved {} bytes", pos); + Ok(pos) + } + + pub(crate) async fn send( + &self, + cid: u16, + buf: &[u8], + hci: &HciController<'_, T>, + ) -> Result<(), AdapterError> { + let mut p_buf = [0u8; L2CAP_MTU]; + let (conn, mps, peer_cid) = + self.with_connected_channel(cid, |_, state| (state.conn, state.mps, state.peer_cid))?; + // The number of packets we'll need to send for this payload + let n_packets = 1 + ((buf.len() as u16).saturating_sub(mps - 2)).div_ceil(mps); + // info!("Sending data of len {} into {} packets", buf.len(), n_packets); + + poll_fn(|cx| self.poll_request_to_send(cid, n_packets, Some(cx))).await?; + + // Segment using mps + let (first, remaining) = buf.split_at(buf.len().min(mps as usize - 2)); + + let len = encode(first, &mut p_buf[..], peer_cid, Some(buf.len() as u16))?; + hci.send(conn, &p_buf[..len]).await?; + + let chunks = remaining.chunks(mps as usize); + let num_chunks = chunks.len(); + + for (i, chunk) in chunks.enumerate() { + let len = encode(chunk, &mut p_buf[..], peer_cid, None)?; + hci.send(conn, &p_buf[..len]).await?; + } + + Ok(()) + } + + pub(crate) fn try_send( + &self, + cid: u16, + buf: &[u8], + hci: &HciController<'_, T>, + ) -> Result<(), AdapterError> { + let mut p_buf = [0u8; L2CAP_MTU]; + let (conn, mps, peer_cid) = + self.with_connected_channel(cid, |_, state| (state.conn, state.mps, state.peer_cid))?; + // The number of packets we'll need to send for this payload + let n_packets = 1 + ((buf.len() as u16).saturating_sub(mps - 2)).div_ceil(mps); + // info!("Sending data of len {} into {} packets", buf.len(), n_packets); + + match self.poll_request_to_send(cid, n_packets, None) { + Poll::Ready(res) => res?, + Poll::Pending => return Err(Error::Busy.into()), + } + + // Segment using mps + let (first, remaining) = buf.split_at(buf.len().min(mps as usize - 2)); + + let len = encode(first, &mut p_buf[..], peer_cid, Some(buf.len() as u16))?; + hci.try_send(conn, &p_buf[..len])?; + + let chunks = remaining.chunks(mps as usize); + let num_chunks = chunks.len(); + + for (i, chunk) in chunks.enumerate() { + let len = encode(chunk, &mut p_buf[..], peer_cid, None)?; + hci.try_send(conn, &p_buf[..len])?; + } + + Ok(()) + } + + async fn flow_control( + &self, + cid: u16, + hci: &HciController<'_, T>, + ) -> Result<(), AdapterError> { + let (conn, credits) = self.state.lock(|state| { let mut state = state.borrow_mut(); for (idx, storage) in state.channels.iter_mut().enumerate() { match storage { ChannelState::Connected(state) if cid == state.cid => { - return Ok(state.flow_control.process().map(|credits| { - ( - state.conn, - L2capLeSignal::new( - next_req_id, - L2capLeSignalData::LeCreditFlowInd(LeCreditFlowInd { - cid: state.cid, - credits, - }), - ), - ) - })); + return Ok((state.conn, state.flow_control.process())); } _ => {} } } Err(Error::NotFound) })?; - Ok(ret) - } - fn disconnect(&self, cid: u16) -> Result<(), Error> { - ChannelManager::disconnect(self, cid) + if let Some(credits) = credits { + let next_req_id = self.next_request_id(); + hci.signal( + conn, + &L2capLeSignal::new( + next_req_id, + L2capLeSignalData::LeCreditFlowInd(LeCreditFlowInd { cid, credits }), + ), + ) + .await?; + } + Ok(()) } fn confirm_disconnected(&self, cid: u16) -> Result<(), Error> { @@ -559,14 +701,14 @@ impl<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP }) } - fn poll_request_to_send(&self, cid: u16, credits: usize, cx: Option<&mut Context<'_>>) -> Poll> { + fn poll_request_to_send(&self, cid: u16, credits: u16, cx: Option<&mut Context<'_>>) -> Poll> { self.state.lock(|state| { let mut state = state.borrow_mut(); for (idx, storage) in state.channels.iter_mut().enumerate() { match storage { ChannelState::Connected(s) if cid == s.cid => { - if credits <= s.peer_credits as usize { - s.peer_credits -= credits as u16; + if credits <= s.peer_credits { + s.peer_credits -= credits; return Poll::Ready(Ok(())); } else { if let Some(cx) = cx { @@ -583,6 +725,23 @@ impl<'d, M: RawMutex, const CHANNELS: usize, const L2CAP_TXQ: usize, const L2CAP } } +fn encode(data: &[u8], packet: &mut [u8], peer_cid: u16, header: Option) -> Result { + let mut w = WriteCursor::new(packet); + if header.is_some() { + w.write(2 + data.len() as u16)?; + } else { + w.write(data.len() as u16)?; + } + w.write(peer_cid)?; + + if let Some(len) = header { + w.write(len)?; + } + + w.append(data)?; + Ok(w.len()) +} + pub enum ChannelState { Disconnected, Connecting(ConnectingState), @@ -659,7 +818,7 @@ impl CreditFlowControl { } } -#[derive(Clone, Debug)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ConnectingState { pub(crate) conn: ConnHandle, @@ -673,7 +832,7 @@ pub struct ConnectingState { pub(crate) mtu: u16, } -#[derive(Clone, Debug)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PeerConnectingState { pub(crate) conn: ConnHandle, @@ -687,7 +846,7 @@ pub struct PeerConnectingState { pub(crate) mtu: u16, } -#[derive(Clone, Debug)] +#[derive(Debug, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ConnectedState { pub(crate) conn: ConnHandle, @@ -703,7 +862,7 @@ pub struct ConnectedState { pub(crate) pool_id: AllocId, } -#[derive(Clone, Debug)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct DisconnectingState { pub(crate) conn: ConnHandle, diff --git a/host/src/connection.rs b/host/src/connection.rs index 7dd3bbf5..adc9d1d4 100644 --- a/host/src/connection.rs +++ b/host/src/connection.rs @@ -1,6 +1,6 @@ use bt_hci::{ cmd::{le::LeConnUpdate, link_control::Disconnect, status::ReadRssi}, - controller::{ControllerCmdAsync, ControllerCmdSync}, + controller::{Controller, ControllerCmdAsync, ControllerCmdSync}, param::{BdAddr, ConnHandle, DisconnectReason, LeConnRole}, }; use embassy_sync::blocking_mutex::raw::RawMutex; @@ -14,7 +14,7 @@ pub use crate::connection_manager::ConnectionInfo; #[derive(Clone)] pub struct Connection { - pub(crate) info: ConnectionInfo, + handle: ConnHandle, } pub struct ConnectConfig<'d> { @@ -43,53 +43,64 @@ impl Default for ConnectParams { } impl Connection { - pub fn handle(&self) -> ConnHandle { - self.info.handle + pub(crate) fn new(handle: ConnHandle) -> Self { + Self { handle } } - pub async fn accept< - M: RawMutex, - T, - const CONNS: usize, - const CHANNELS: usize, - const L2CAP_TXQ: usize, - const L2CAP_RXQ: usize, - >( - adapter: &Adapter<'_, M, T, CONNS, CHANNELS, L2CAP_TXQ, L2CAP_RXQ>, - ) -> Self { - let info = adapter.connections.accept(&[]).await; - Connection { info } + pub fn handle(&self) -> ConnHandle { + self.handle } pub async fn disconnect< M: RawMutex, - T, + T: Controller + ControllerCmdSync, const CONNS: usize, const CHANNELS: usize, + const L2CAP_MTU: usize, const L2CAP_TXQ: usize, const L2CAP_RXQ: usize, >( &mut self, - adapter: &Adapter<'_, M, T, CONNS, CHANNELS, L2CAP_TXQ, L2CAP_RXQ>, - ) -> Result<(), AdapterError> - where - T: ControllerCmdSync, - { + adapter: &Adapter<'_, M, T, CONNS, CHANNELS, L2CAP_MTU, L2CAP_TXQ, L2CAP_RXQ>, + ) -> Result<(), AdapterError> { adapter - .command(Disconnect::new( - self.info.handle, - DisconnectReason::RemoteUserTerminatedConn, - )) + .command(Disconnect::new(self.handle, DisconnectReason::RemoteUserTerminatedConn)) .await?; Ok(()) } - pub fn role(&self) -> LeConnRole { - self.info.role + pub fn role< + M: RawMutex, + T: Controller, + const CONNS: usize, + const CHANNELS: usize, + const L2CAP_MTU: usize, + const L2CAP_TXQ: usize, + const L2CAP_RXQ: usize, + >( + &self, + adapter: &Adapter<'_, M, T, CONNS, CHANNELS, L2CAP_MTU, L2CAP_TXQ, L2CAP_RXQ>, + ) -> Result> { + let role = adapter.connections.with_connection(self.handle, |info| info.role)?; + Ok(role) } - pub fn peer_address(&self) -> BdAddr { - self.info.peer_address + pub fn peer_address< + M: RawMutex, + T: Controller, + const CONNS: usize, + const CHANNELS: usize, + const L2CAP_MTU: usize, + const L2CAP_TXQ: usize, + const L2CAP_RXQ: usize, + >( + &self, + adapter: &Adapter<'_, M, T, CONNS, CHANNELS, L2CAP_MTU, L2CAP_TXQ, L2CAP_RXQ>, + ) -> Result> { + let role = adapter + .connections + .with_connection(self.handle, |info| info.peer_address)?; + Ok(role) } pub async fn rssi< @@ -106,7 +117,7 @@ impl Connection { where T: ControllerCmdSync, { - let ret = adapter.command(ReadRssi::new(self.info.handle)).await?; + let ret = adapter.command(ReadRssi::new(self.handle)).await?; Ok(ret.rssi) } @@ -127,7 +138,7 @@ impl Connection { { adapter .async_command(LeConnUpdate::new( - self.info.handle, + self.handle, params.min_connection_interval.into(), params.max_connection_interval.into(), params.max_latency, diff --git a/host/src/connection_manager.rs b/host/src/connection_manager.rs index 13c2e383..4690b918 100644 --- a/host/src/connection_manager.rs +++ b/host/src/connection_manager.rs @@ -53,12 +53,29 @@ impl ConnectionManager { }) } + pub(crate) fn with_connection R, R>( + &self, + handle: ConnHandle, + f: F, + ) -> Result { + self.state.lock(|state| { + let state = state.borrow(); + for storage in state.connections.iter() { + match storage { + ConnectionState::Connected(h, info) if *h == handle => return Ok(f(info)), + _ => {} + } + } + Err(Error::NotFound) + }) + } + pub fn connect(&self, handle: ConnHandle, info: ConnectionInfo) -> Result<(), Error> { self.state.lock(|state| { let mut state = state.borrow_mut(); for storage in state.connections.iter_mut() { if let ConnectionState::Disconnected = storage { - *storage = ConnectionState::Connecting(handle, info); + *storage = ConnectionState::Connecting(handle, Some(info)); state.waker.wake(); return Ok(()); } @@ -76,23 +93,24 @@ impl ConnectionManager { self.canceled.signal(()); } - pub fn poll_accept(&self, peers: &[(AddrKind, &BdAddr)], cx: &mut Context<'_>) -> Poll { + pub fn poll_accept(&self, peers: &[(AddrKind, &BdAddr)], cx: &mut Context<'_>) -> Poll { self.state.lock(|state| { let mut state = state.borrow_mut(); for storage in state.connections.iter_mut() { if let ConnectionState::Connecting(handle, info) = storage { + let handle = *handle; if !peers.is_empty() { for peer in peers.iter() { - if info.peer_addr_kind == peer.0 && &info.peer_address == peer.1 { - let i = *info; - *storage = ConnectionState::Connected(*handle, *info); - return Poll::Ready(i); + if info.as_ref().unwrap().peer_addr_kind == peer.0 + && &info.as_ref().unwrap().peer_address == peer.1 + { + *storage = ConnectionState::Connected(handle, info.take().unwrap()); + return Poll::Ready(handle); } } } else { - let i = *info; - *storage = ConnectionState::Connected(*handle, *info); - return Poll::Ready(i); + *storage = ConnectionState::Connected(handle, info.take().unwrap()); + return Poll::Ready(handle); } } } @@ -101,28 +119,14 @@ impl ConnectionManager { }) } - pub async fn accept(&self, peers: &[(AddrKind, &BdAddr)]) -> ConnectionInfo { + pub async fn accept(&self, peers: &[(AddrKind, &BdAddr)]) -> ConnHandle { poll_fn(move |cx| self.poll_accept(peers, cx)).await } - - pub fn info(&self, handle: ConnHandle) -> Result { - self.state.lock(|state| { - let mut state = state.borrow_mut(); - for storage in state.connections.iter_mut() { - if let ConnectionState::Connected(h, info) = storage { - if *h == handle { - return Ok(*info); - } - } - } - Err(Error::NotFound) - }) - } } pub enum ConnectionState { Disconnected, - Connecting(ConnHandle, ConnectionInfo), + Connecting(ConnHandle, Option), Connected(ConnHandle, ConnectionInfo), } @@ -163,7 +167,7 @@ impl DynamicConnectionManager for ConnectionMan } } -#[derive(Clone, Copy, Debug)] +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ConnectionInfo { pub handle: ConnHandle, diff --git a/host/src/l2cap.rs b/host/src/l2cap.rs index 7914b0dd..ff4f638c 100644 --- a/host/src/l2cap.rs +++ b/host/src/l2cap.rs @@ -1,24 +1,18 @@ use core::cell::RefCell; -use core::future::poll_fn; -use crate::adapter::{Adapter, HciController}; -use crate::channel_manager::DynamicChannelManager; +use crate::adapter::Adapter; +pub use crate::channel_manager::CreditFlowPolicy; use crate::codec; use crate::connection::Connection; -use crate::cursor::{ReadCursor, WriteCursor}; -use crate::packet_pool::{AllocId, DynamicPacketPool, Packet}; -use crate::pdu::Pdu; +use crate::cursor::ReadCursor; +use crate::packet_pool::Packet; use crate::{AdapterError, Error}; use bt_hci::cmd::link_control::Disconnect; use bt_hci::controller::{Controller, ControllerCmdSync}; use bt_hci::data::AclPacket; use bt_hci::param::ConnHandle; use bt_hci::param::DisconnectReason; -use core::task::Poll; use embassy_sync::blocking_mutex::raw::RawMutex; -use embassy_sync::channel::DynamicReceiver; - -pub use crate::channel_manager::CreditFlowPolicy; pub(crate) const L2CAP_CID_ATT: u16 = 0x0004; pub(crate) const L2CAP_CID_LE_U_SIGNAL: u16 = 0x0005; @@ -142,243 +136,127 @@ impl L2capHeader { } } -pub struct L2capChannel<'a, 'd, T: Controller, const L2CAP_MTU: usize = 27> { - conn: ConnHandle, - pool_id: AllocId, +#[derive(Clone)] +pub struct L2capChannel { + handle: ConnHandle, cid: u16, - peer_cid: u16, - mps: usize, - pool: &'d dyn DynamicPacketPool<'d>, - manager: &'a dyn DynamicChannelManager<'d>, - rx: DynamicReceiver<'a, Option>>, - hci: HciController<'a, T>, -} - -impl<'a, 'd, T: Controller, const L2CAP_MTU: usize> Clone for L2capChannel<'a, 'd, T, L2CAP_MTU> { - fn clone(&self) -> Self { - Self { - conn: self.conn, - pool_id: self.pool_id, - cid: self.cid, - peer_cid: self.peer_cid, - mps: self.mps, - pool: self.pool, - manager: self.manager, - rx: self.rx, - hci: self.hci.clone(), - } - } } -impl<'a, 'd, T: Controller, const L2CAP_MTU: usize> L2capChannel<'a, 'd, T, L2CAP_MTU> { - fn encode(&self, data: &[u8], packet: &mut [u8], header: Option) -> Result { - let mut w = WriteCursor::new(packet); - if header.is_some() { - w.write(2 + data.len() as u16)?; - } else { - w.write(data.len() as u16)?; - } - w.write(self.peer_cid)?; - - if let Some(len) = header { - w.write(len)?; - } - - w.append(data)?; - Ok(w.len()) - } - - pub async fn send(&mut self, buf: &[u8]) -> Result<(), AdapterError> { - let mut p_buf = [0u8; L2CAP_MTU]; - assert!(p_buf.len() >= self.mps + 4); - // The number of packets we'll need to send for this payload - let n_packets = 1 + (buf.len().saturating_sub(self.mps - 2)).div_ceil(self.mps); - // info!("Sending data of len {} into {} packets", buf.len(), n_packets); - - poll_fn(|cx| self.manager.poll_request_to_send(self.cid, n_packets, Some(cx))).await?; - - // Segment using mps - let (first, remaining) = buf.split_at(buf.len().min(self.mps - 2)); - - let len = self.encode(first, &mut p_buf[..], Some(buf.len() as u16))?; - self.hci.send(self.conn, &p_buf[..len]).await?; - - let chunks = remaining.chunks(self.mps); - let num_chunks = chunks.len(); - - for (i, chunk) in chunks.enumerate() { - let len = self.encode(chunk, &mut p_buf[..], None)?; - self.hci.send(self.conn, &p_buf[..len]).await?; - } - - Ok(()) - } - - pub fn try_send(&mut self, buf: &[u8]) -> Result<(), AdapterError> { - let mut p_buf = [0u8; L2CAP_MTU]; - assert!(p_buf.len() >= self.mps + 4); - - // The number of packets we'll need to send for this payload - let n_packets = 1 + (buf.len().saturating_sub(self.mps - 2)).div_ceil(self.mps); - //info!("Sending data of len {} into {} packets", buf.len(), n_packets); - - match self.manager.poll_request_to_send(self.cid, n_packets, None) { - Poll::Ready(res) => res?, - Poll::Pending => return Err(Error::Busy.into()), - } - - // Segment using mps - let (first, remaining) = buf.split_at(buf.len().min(self.mps - 2)); - - let len = self.encode(first, &mut p_buf[..], Some(buf.len() as u16))?; - self.hci.try_send(self.conn, &p_buf[..len])?; - - let chunks = remaining.chunks(self.mps); - let num_chunks = chunks.len(); - - for (i, chunk) in chunks.enumerate() { - let len = self.encode(chunk, &mut p_buf[..], None)?; - self.hci.try_send(self.conn, &p_buf[..len])?; - } - - Ok(()) - } - - async fn receive_pdu(&mut self) -> Result, AdapterError> { - match self.rx.receive().await { - Some(pdu) => Ok(pdu), - None => { - self.manager.confirm_disconnected(self.cid)?; - Err(Error::ChannelClosed.into()) - } - } +impl L2capChannel { + pub async fn send< + M: RawMutex, + T: Controller, + const CONNS: usize, + const CHANNELS: usize, + const L2CAP_MTU: usize, + const L2CAP_TXQ: usize, + const L2CAP_RXQ: usize, + >( + &mut self, + adapter: &Adapter<'_, M, T, CONNS, CHANNELS, L2CAP_MTU, L2CAP_TXQ, L2CAP_RXQ>, + buf: &[u8], + ) -> Result<(), AdapterError> { + adapter.channels.send(self.cid, buf, &adapter.hci()).await } - pub async fn receive(&mut self, buf: &mut [u8]) -> Result> { - let mut n_received = 1; - let packet = self.receive_pdu().await?; - let len = packet.len; - - let mut r = ReadCursor::new(packet.as_ref()); - let remaining: u16 = r.read()?; - // info!("Total expected: {}", remaining); - - let data = r.remaining(); - let to_copy = data.len().min(buf.len()); - buf[..to_copy].copy_from_slice(&data[..to_copy]); - let mut pos = to_copy; - - // info!("Received {} bytes so far", pos); - - let mut remaining = remaining as usize - data.len(); - - drop(packet); - self.flow_control().await?; - //info!( - // "Total size of PDU is {}, read buffer size is {} remaining; {}", - // len, - // buf.len(), - // remaining - //); - // We have some k-frames to reassemble - while remaining > 0 { - let packet = self.receive_pdu().await?; - n_received += 1; - let to_copy = packet.len.min(buf.len() - pos); - if to_copy > 0 { - buf[pos..pos + to_copy].copy_from_slice(&packet.as_ref()[..to_copy]); - pos += to_copy; - } - remaining -= packet.len; - drop(packet); - self.flow_control().await?; - } - - // info!("Total reserved {} bytes", pos); - Ok(pos) + pub fn try_send< + M: RawMutex, + T: Controller, + const CONNS: usize, + const CHANNELS: usize, + const L2CAP_MTU: usize, + const L2CAP_TXQ: usize, + const L2CAP_RXQ: usize, + >( + &mut self, + adapter: &Adapter<'_, M, T, CONNS, CHANNELS, L2CAP_MTU, L2CAP_TXQ, L2CAP_RXQ>, + buf: &[u8], + ) -> Result<(), AdapterError> { + adapter.channels.try_send(self.cid, buf, &adapter.hci()) } - async fn flow_control(&mut self) -> Result<(), AdapterError> { - if let Some((handle, response)) = self.manager.flow_control(self.cid)? { - self.hci.signal(handle, response).await?; - } - Ok(()) + pub async fn receive< + M: RawMutex, + T: Controller, + const CONNS: usize, + const CHANNELS: usize, + const L2CAP_MTU: usize, + const L2CAP_TXQ: usize, + const L2CAP_RXQ: usize, + >( + &mut self, + adapter: &Adapter<'_, M, T, CONNS, CHANNELS, L2CAP_MTU, L2CAP_TXQ, L2CAP_RXQ>, + buf: &mut [u8], + ) -> Result> { + adapter.channels.receive(self.cid, buf, &adapter.hci()).await } pub async fn accept< M: RawMutex, + T: Controller, const CONNS: usize, const CHANNELS: usize, + const L2CAP_MTU: usize, const L2CAP_TXQ: usize, const L2CAP_RXQ: usize, >( - adapter: &'a Adapter<'d, M, T, CONNS, CHANNELS, L2CAP_TXQ, L2CAP_RXQ>, + adapter: &Adapter<'_, M, T, CONNS, CHANNELS, L2CAP_MTU, L2CAP_TXQ, L2CAP_RXQ>, connection: &Connection, psm: &[u16], mtu: u16, flow_policy: CreditFlowPolicy, - ) -> Result, AdapterError> { - let connections = &adapter.connections; - let channels = &adapter.channels; - - let (state, rx) = channels - .accept(connection.handle(), psm, mtu, flow_policy, &adapter.hci()) + ) -> Result> { + let handle = connection.handle(); + let cid = adapter + .channels + .accept(handle, psm, mtu, flow_policy, &adapter.hci()) .await?; - Ok(Self { - conn: connection.handle(), - cid: state.cid, - peer_cid: state.peer_cid, - mps: state.mps as usize, - pool: adapter.pool, - pool_id: state.pool_id, - manager: &adapter.channels, - hci: adapter.hci(), - rx, - }) + Ok(Self { cid, handle }) } - pub fn disconnect(&self, close_connection: bool) -> Result<(), AdapterError> - where - T: ControllerCmdSync, - { - self.manager.disconnect(self.cid)?; + pub fn disconnect< + M: RawMutex, + T: Controller + ControllerCmdSync, + const CONNS: usize, + const CHANNELS: usize, + const L2CAP_MTU: usize, + const L2CAP_TXQ: usize, + const L2CAP_RXQ: usize, + >( + &mut self, + adapter: &Adapter<'_, M, T, CONNS, CHANNELS, L2CAP_MTU, L2CAP_TXQ, L2CAP_RXQ>, + close_connection: bool, + ) -> Result<(), AdapterError> { + adapter.channels.disconnect(self.cid)?; if close_connection { - self.hci - .try_command(Disconnect::new(self.conn, DisconnectReason::RemoteUserTerminatedConn))?; + adapter.try_command(Disconnect::new(self.handle, DisconnectReason::RemoteUserTerminatedConn))?; } Ok(()) } pub async fn create< M: RawMutex, + T: Controller, const CONNS: usize, const CHANNELS: usize, + const L2CAP_MTU: usize, const L2CAP_TXQ: usize, const L2CAP_RXQ: usize, >( - adapter: &'a Adapter<'d, M, T, CONNS, CHANNELS, L2CAP_TXQ, L2CAP_RXQ>, + adapter: &Adapter<'_, M, T, CONNS, CHANNELS, L2CAP_MTU, L2CAP_TXQ, L2CAP_RXQ>, connection: &Connection, psm: u16, mtu: u16, flow_policy: CreditFlowPolicy, ) -> Result> where { - let (state, rx) = adapter + let handle = connection.handle(); + let cid = adapter .channels .create(connection.handle(), psm, mtu, flow_policy, &adapter.hci()) .await?; - Ok(Self { - conn: connection.handle(), - pool_id: state.pool_id, - cid: state.cid, - peer_cid: state.peer_cid, - mps: state.mps as usize, - pool: adapter.pool, - manager: &adapter.channels, - hci: adapter.hci(), - rx, - }) + Ok(Self { handle, cid }) } } diff --git a/host/tests/l2cap.rs b/host/tests/l2cap.rs index 880f9ee2..302f0a4a 100644 --- a/host/tests/l2cap.rs +++ b/host/tests/l2cap.rs @@ -72,7 +72,7 @@ async fn l2cap_connection_oriented_channels() { let mut host_resources: HostResources = HostResources::new(PacketQos::Guaranteed(4)); - let adapter: Adapter<'_, NoopRawMutex, _, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX> = + let adapter: Adapter<'_, NoopRawMutex, _, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, 27> = Adapter::new(controller_peripheral, &mut host_resources); select! { @@ -99,8 +99,7 @@ async fn l2cap_connection_oriented_channels() { }).await?; println!("[peripheral] connected"); - let mut ch1: L2capChannel<'_, '_, _, 27> = - L2capChannel::accept(&adapter, &conn, &[0x2349], PAYLOAD_LEN as u16, Default::default()).await?; + let mut ch1 = L2capChannel::accept(&adapter, &conn, &[0x2349], PAYLOAD_LEN as u16, Default::default()).await?; println!("[peripheral] channel created"); @@ -108,7 +107,7 @@ async fn l2cap_connection_oriented_channels() { const PAYLOAD_LEN: usize = 27; let mut rx = [0; PAYLOAD_LEN]; for i in 0..10 { - let len = ch1.receive(&mut rx).await?; + let len = ch1.receive(&adapter, &mut rx).await?; assert_eq!(len, rx.len()); assert_eq!(rx, [i; PAYLOAD_LEN]); } @@ -117,7 +116,7 @@ async fn l2cap_connection_oriented_channels() { tokio::time::sleep(Duration::from_secs(1)).await; for i in 0..10 { let tx = [i; PAYLOAD_LEN]; - ch1.send(&tx).await?; + ch1.send(&adapter, &tx).await?; } println!("[peripheral] data sent"); break; @@ -135,7 +134,7 @@ async fn l2cap_connection_oriented_channels() { let mut host_resources: HostResources = HostResources::new(PacketQos::Guaranteed(4)); - let adapter: Adapter<'_, NoopRawMutex, _, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX> = + let adapter: Adapter<'_, NoopRawMutex, _, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX, 27> = Adapter::new(controller_central, &mut host_resources); select! { @@ -169,17 +168,16 @@ async fn l2cap_connection_oriented_channels() { let conn = adapter.connect(&config).await.unwrap(); println!("[central] connected"); const PAYLOAD_LEN: usize = 27; - let mut ch1: L2capChannel<'_, '_, _, 27> = - L2capChannel::create(&adapter, &conn, 0x2349, PAYLOAD_LEN as u16, Default::default()).await?; + let mut ch1 = L2capChannel::create(&adapter, &conn, 0x2349, PAYLOAD_LEN as u16, Default::default()).await?; println!("[central] channel created"); for i in 0..10 { let tx = [i; PAYLOAD_LEN]; - ch1.send(&tx).await?; + ch1.send(&adapter, &tx).await?; } println!("[central] data sent"); let mut rx = [0; PAYLOAD_LEN]; for i in 0..10 { - let len = ch1.receive(&mut rx).await?; + let len = ch1.receive(&adapter, &mut rx).await?; assert_eq!(len, rx.len()); assert_eq!(rx, [i; PAYLOAD_LEN]); }