use bt_hci::controller::{blocking, Controller};
pub use crate::channel_manager::CreditFlowPolicy;
#[cfg(feature = "channel-metrics")]
pub use crate::channel_manager::Metrics as ChannelMetrics;
use crate::channel_manager::{ChannelIndex, ChannelManager};
use crate::connection::Connection;
use crate::pdu::Sdu;
use crate::{BleHostError, Error, PacketPool, Stack};
pub(crate) mod sar;
pub struct L2capChannel<'d, P: PacketPool> {
index: ChannelIndex,
manager: &'d ChannelManager<'d, P>,
}
pub struct L2capChannelWriter<'d, P: PacketPool> {
index: ChannelIndex,
manager: &'d ChannelManager<'d, P>,
}
pub struct L2capChannelReader<'d, P: PacketPool> {
index: ChannelIndex,
manager: &'d ChannelManager<'d, P>,
}
pub struct L2capChannelRef<'d, P: PacketPool> {
index: ChannelIndex,
manager: &'d ChannelManager<'d, P>,
}
#[cfg(feature = "defmt")]
impl<P: PacketPool> defmt::Format for L2capChannel<'_, P> {
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "{}, ", self.index);
self.manager.print(self.index, f);
}
}
impl<P: PacketPool> Drop for L2capChannel<'_, P> {
fn drop(&mut self) {
self.manager.dec_ref(self.index);
}
}
impl<P: PacketPool> Drop for L2capChannelRef<'_, P> {
fn drop(&mut self) {
self.manager.dec_ref(self.index);
}
}
#[cfg(feature = "defmt")]
impl<P: PacketPool> defmt::Format for L2capChannelWriter<'_, P> {
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "{}, ", self.index);
self.manager.print(self.index, f);
}
}
impl<P: PacketPool> Drop for L2capChannelWriter<'_, P> {
fn drop(&mut self) {
self.manager.dec_ref(self.index);
}
}
#[cfg(feature = "defmt")]
impl<P: PacketPool> defmt::Format for L2capChannelReader<'_, P> {
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "{}, ", self.index);
self.manager.print(self.index, f);
}
}
impl<P: PacketPool> Drop for L2capChannelReader<'_, P> {
fn drop(&mut self) {
self.manager.dec_ref(self.index);
}
}
#[derive(Default)]
pub struct L2capChannelConfig {
pub mtu: Option<u16>,
pub mps: Option<u16>,
pub flow_policy: CreditFlowPolicy,
pub initial_credits: Option<u16>,
}
impl<'d, P: PacketPool> L2capChannel<'d, P> {
pub(crate) fn new(index: ChannelIndex, manager: &'d ChannelManager<'d, P>) -> Self {
Self { index, manager }
}
pub fn disconnect(&mut self) {
self.manager.disconnect(self.index);
}
pub fn psm(&self) -> u16 {
self.manager.psm(self.index)
}
pub async fn send<T: Controller>(
&mut self,
stack: &Stack<'_, T, P>,
buf: &[u8],
) -> Result<(), BleHostError<T::Error>> {
let mut p_buf = P::allocate().ok_or(Error::OutOfMemory)?;
stack
.host
.channels
.send(self.index, buf, p_buf.as_mut(), &stack.host)
.await
}
pub fn try_send<T: Controller + blocking::Controller>(
&mut self,
stack: &Stack<'_, T, P>,
buf: &[u8],
) -> Result<(), BleHostError<T::Error>> {
let mut p_buf = P::allocate().ok_or(Error::OutOfMemory)?;
stack
.host
.channels
.try_send(self.index, buf, p_buf.as_mut(), &stack.host)
}
pub async fn receive<T: Controller>(
&mut self,
stack: &Stack<'_, T, P>,
buf: &mut [u8],
) -> Result<usize, BleHostError<T::Error>> {
stack.host.channels.receive(self.index, buf, &stack.host).await
}
pub async fn receive_sdu<T: Controller>(
&mut self,
stack: &Stack<'_, T, P>,
) -> Result<Sdu<P::Packet>, BleHostError<T::Error>> {
stack.host.channels.receive_sdu(self.index, &stack.host).await
}
#[cfg(feature = "channel-metrics")]
pub fn metrics<F: FnOnce(&ChannelMetrics) -> R, R>(&self, f: F) -> R {
self.manager.metrics(self.index, f)
}
pub async fn accept<T: Controller>(
stack: &'d Stack<'d, T, P>,
connection: &Connection<'_, P>,
psm: &[u16],
config: &L2capChannelConfig,
) -> Result<Self, BleHostError<T::Error>> {
let handle = connection.handle();
stack.host.channels.accept(handle, psm, config, &stack.host).await
}
pub async fn create<T: Controller>(
stack: &'d Stack<'d, T, P>,
connection: &Connection<'_, P>,
psm: u16,
config: &L2capChannelConfig,
) -> Result<Self, BleHostError<T::Error>> {
stack
.host
.channels
.create(connection.handle(), psm, config, &stack.host)
.await
}
pub fn split(self) -> (L2capChannelWriter<'d, P>, L2capChannelReader<'d, P>) {
self.manager.inc_ref(self.index);
self.manager.inc_ref(self.index);
(
L2capChannelWriter {
index: self.index,
manager: self.manager,
},
L2capChannelReader {
index: self.index,
manager: self.manager,
},
)
}
pub fn merge(writer: L2capChannelWriter<'d, P>, reader: L2capChannelReader<'d, P>) -> Self {
assert_eq!(writer.index, reader.index);
let manager = writer.manager;
let index = writer.index;
manager.inc_ref(index);
Self { index, manager }
}
}
impl<'d, P: PacketPool> L2capChannelReader<'d, P> {
pub fn disconnect(&mut self) {
self.manager.disconnect(self.index);
}
pub async fn receive<T: Controller>(
&mut self,
stack: &Stack<'_, T, P>,
buf: &mut [u8],
) -> Result<usize, BleHostError<T::Error>> {
stack.host.channels.receive(self.index, buf, &stack.host).await
}
pub async fn receive_sdu<T: Controller>(
&mut self,
stack: &Stack<'_, T, P>,
) -> Result<Sdu<P::Packet>, BleHostError<T::Error>> {
stack.host.channels.receive_sdu(self.index, &stack.host).await
}
#[cfg(feature = "channel-metrics")]
pub fn metrics<F: FnOnce(&ChannelMetrics) -> R, R>(&self, f: F) -> R {
self.manager.metrics(self.index, f)
}
pub fn channel_ref(&mut self) -> L2capChannelRef<'d, P> {
self.manager.inc_ref(self.index);
L2capChannelRef {
index: self.index,
manager: self.manager,
}
}
}
impl<'d, P: PacketPool> L2capChannelRef<'d, P> {
#[cfg(feature = "channel-metrics")]
pub fn metrics<F: FnOnce(&ChannelMetrics) -> R, R>(&self, f: F) -> R {
self.manager.metrics(self.index, f)
}
}
impl<'d, P: PacketPool> L2capChannelWriter<'d, P> {
pub fn disconnect(&mut self) {
self.manager.disconnect(self.index);
}
pub async fn send<T: Controller>(
&mut self,
stack: &Stack<'_, T, P>,
buf: &[u8],
) -> Result<(), BleHostError<T::Error>> {
let mut p_buf = P::allocate().ok_or(Error::OutOfMemory)?;
stack
.host
.channels
.send(self.index, buf, p_buf.as_mut(), &stack.host)
.await
}
pub fn try_send<T: Controller + blocking::Controller>(
&mut self,
stack: &Stack<'_, T, P>,
buf: &[u8],
) -> Result<(), BleHostError<T::Error>> {
let mut p_buf = P::allocate().ok_or(Error::OutOfMemory)?;
stack
.host
.channels
.try_send(self.index, buf, p_buf.as_mut(), &stack.host)
}
#[cfg(feature = "channel-metrics")]
pub fn metrics<F: FnOnce(&ChannelMetrics) -> R, R>(&self, f: F) -> R {
self.manager.metrics(self.index, f)
}
pub fn channel_ref(&mut self) -> L2capChannelRef<'d, P> {
self.manager.inc_ref(self.index);
L2capChannelRef {
index: self.index,
manager: self.manager,
}
}
}