Skip to content

Commit

Permalink
Merge pull request #29 from embassy-rs/l2cap-fixes
Browse files Browse the repository at this point in the history
improve credit handling
  • Loading branch information
lulf authored May 9, 2024
2 parents c08007c + 6d8f353 commit aee57bf
Show file tree
Hide file tree
Showing 4 changed files with 293 additions and 114 deletions.
73 changes: 45 additions & 28 deletions host/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//!
//! The adapter module contains the main entry point for the TrouBLE host.
use core::future::poll_fn;
use core::task::Poll;

use bt_hci::cmd::controller_baseband::{HostBufferSize, Reset, SetEventMask};
use bt_hci::cmd::le::{
Expand All @@ -22,10 +23,9 @@ use bt_hci::param::{
};
use bt_hci::{ControllerToHostPacket, FromHciBytes, WriteHci};
use embassy_futures::select::{select, Either};
use embassy_sync::blocking_mutex::raw::{NoopRawMutex, RawMutex};
use embassy_sync::blocking_mutex::raw::RawMutex;
use embassy_sync::channel::Channel;
use embassy_sync::once_lock::OnceLock;
use embassy_sync::semaphore::{GreedySemaphore, Semaphore as _};
use futures::pin_mut;

use crate::advertise::{Advertisement, AdvertisementConfig, RawAdvertisement};
Expand Down Expand Up @@ -95,7 +95,6 @@ pub struct Adapter<
pub(crate) channels: ChannelManager<'d, M, CHANNELS, L2CAP_MTU, L2CAP_TXQ, L2CAP_RXQ>,
pub(crate) att_inbound: Channel<M, (ConnHandle, Pdu<'d>), L2CAP_RXQ>,
pub(crate) pool: &'d dyn DynamicPacketPool<'d>,
pub(crate) permits: GreedySemaphore<NoopRawMutex>,

pub(crate) scanner: Channel<M, Option<ScanReport>, 1>,
}
Expand Down Expand Up @@ -132,7 +131,6 @@ where
pool: &host_resources.pool,
att_inbound: Channel::new(),
scanner: Channel::new(),
permits: GreedySemaphore::new(0),
}
}

Expand Down Expand Up @@ -589,6 +587,7 @@ where
}

let Some(mut p) = self.pool.alloc(AllocId::from_channel(header.channel)) else {
trace!("No memory for packets on channel {}", header.channel);
return Err(Error::OutOfMemory);
};
p.as_mut()[..data.len()].copy_from_slice(data);
Expand Down Expand Up @@ -719,9 +718,14 @@ where
.await?;

let ret = LeReadBufferSize::new().exec(&self.controller).await?;
self.permits.set(ret.total_num_le_acl_data_packets as usize);
// TODO: Configure ACL max buffer size as well?
info!(
"[adapter] setting permits to {}",
ret.total_num_le_acl_data_packets as usize
);

self.connections
.set_link_credits(ret.total_num_le_acl_data_packets as usize);
// TODO: Configure ACL max buffer size as well?
let _ = self.initialized.init(());

loop {
Expand Down Expand Up @@ -788,8 +792,17 @@ where
let _ = self.channels.disconnected(e.handle);
}
Event::NumberOfCompletedPackets(c) => {
// info!("Confirmed {} packets sent", c.completed_packets.len());
self.permits.release(c.completed_packets.len());
// Explicitly ignoring for now
for entry in c.completed_packets.iter() {
match (entry.handle(), entry.num_completed_packets()) {
(Ok(handle), Ok(completed)) => {
let _ = self.connections.confirm_sent(handle, completed as usize);
}
_ => {} // Ignoring for now
}

//c.completed_packets.len());
}
}
Event::Vendor(vendor) => {
if let Some(handler) = vendor_handler {
Expand Down Expand Up @@ -821,38 +834,41 @@ where
}
}

pub(crate) fn hci(&self) -> HciController<'_, T> {
pub(crate) fn hci(&self) -> HciController<'_, M, T, CONNS> {
HciController {
controller: &self.controller,
permits: &self.permits,
connections: &self.connections,
}
}
}

pub struct HciController<'d, T: Controller> {
pub struct HciController<'d, M: RawMutex, T: Controller, const CONNS: usize> {
pub(crate) controller: &'d T,
pub(crate) permits: &'d GreedySemaphore<NoopRawMutex>,
pub(crate) connections: &'d ConnectionManager<M, CONNS>,
}

impl<'d, T: Controller> Clone for HciController<'d, T> {
impl<'d, M: RawMutex, T: Controller, const CONNS: usize> Clone for HciController<'d, M, T, CONNS> {
fn clone(&self) -> Self {
Self {
controller: self.controller,
permits: self.permits,
connections: self.connections,
}
}
}

impl<'d, T: Controller> HciController<'d, T> {
impl<'d, M: RawMutex, T: Controller, const CONNS: usize> HciController<'d, M, T, CONNS> {
pub(crate) fn try_send(&self, handle: ConnHandle, pdu: &[u8]) -> Result<(), AdapterError<T::Error>>
where
T: blocking::Controller,
{
// info!("[try_send] permits: {}", self.permits.permits());
let permit = self
.permits
.try_acquire(1)
.ok_or::<AdapterError<T::Error>>(Error::NoPermits.into())?;
let mut grant = match self.connections.poll_request_to_send(handle, 1, None) {
Poll::Ready(res) => res?,
Poll::Pending => {
warn!("[link][handle = {}]: not enough credits", handle);
return Err(Error::Busy.into());
}
};

let acl = AclPacket::new(
handle,
AclPacketBoundary::FirstNonFlushable,
Expand All @@ -862,7 +878,7 @@ impl<'d, T: Controller> HciController<'d, T> {
// info!("Sent ACL {:?}", acl);
match self.controller.try_write_acl_data(&acl) {
Ok(result) => {
permit.disarm();
grant.confirm(1);
Ok(result)
}
Err(blocking::TryError::Busy) => {
Expand All @@ -874,12 +890,7 @@ impl<'d, T: Controller> HciController<'d, T> {
}

pub(crate) async fn send(&self, handle: ConnHandle, pdu: &[u8]) -> Result<(), AdapterError<T::Error>> {
// info!("[send] permits: {}", self.permits.permits());
let permit = self
.permits
.acquire(1)
.await
.map_err(|_| AdapterError::Adapter(Error::NoPermits))?;
let mut grant = poll_fn(|cx| self.connections.poll_request_to_send(handle, 1, Some(cx))).await?;
let acl = AclPacket::new(
handle,
AclPacketBoundary::FirstNonFlushable,
Expand All @@ -890,7 +901,7 @@ impl<'d, T: Controller> HciController<'d, T> {
.write_acl_data(&acl)
.await
.map_err(AdapterError::Controller)?;
permit.disarm();
grant.confirm(1);
Ok(())
}

Expand All @@ -901,6 +912,12 @@ impl<'d, T: Controller> HciController<'d, T> {
signal: &D,
p_buf: &mut [u8],
) -> Result<(), AdapterError<T::Error>> {
trace!(
"[l2cap][conn = {}] sending control signal (req = {}) signal: {:?}",
handle,
identifier,
signal
);
let header = L2capSignalHeader {
identifier,
code: D::code(),
Expand Down
Loading

0 comments on commit aee57bf

Please sign in to comment.