trouble_host/
l2cap.rs

1//! L2CAP channels.
2use bt_hci::controller::{blocking, Controller};
3
4pub use crate::channel_manager::CreditFlowPolicy;
5#[cfg(feature = "channel-metrics")]
6pub use crate::channel_manager::Metrics as ChannelMetrics;
7use crate::channel_manager::{ChannelIndex, ChannelManager};
8use crate::connection::Connection;
9use crate::pdu::Sdu;
10use crate::{BleHostError, Error, PacketPool, Stack};
11
12pub(crate) mod sar;
13
14/// Handle representing an L2CAP channel.
15pub struct L2capChannel<'d, P: PacketPool> {
16    index: ChannelIndex,
17    manager: &'d ChannelManager<'d, P>,
18}
19
20/// Handle representing an L2CAP channel write endpoint.
21pub struct L2capChannelWriter<'d, P: PacketPool> {
22    index: ChannelIndex,
23    manager: &'d ChannelManager<'d, P>,
24}
25
26/// Handle representing an L2CAP channel write endpoint.
27pub struct L2capChannelReader<'d, P: PacketPool> {
28    index: ChannelIndex,
29    manager: &'d ChannelManager<'d, P>,
30}
31
32/// Handle to an L2CAP channel for checking it's state.
33pub struct L2capChannelRef<'d, P: PacketPool> {
34    index: ChannelIndex,
35    manager: &'d ChannelManager<'d, P>,
36}
37
38#[cfg(feature = "defmt")]
39impl<P: PacketPool> defmt::Format for L2capChannel<'_, P> {
40    fn format(&self, f: defmt::Formatter<'_>) {
41        defmt::write!(f, "{}, ", self.index);
42        self.manager.print(self.index, f);
43    }
44}
45
46impl<P: PacketPool> Drop for L2capChannel<'_, P> {
47    fn drop(&mut self) {
48        self.manager.dec_ref(self.index);
49    }
50}
51
52impl<P: PacketPool> Drop for L2capChannelRef<'_, P> {
53    fn drop(&mut self) {
54        self.manager.dec_ref(self.index);
55    }
56}
57
58#[cfg(feature = "defmt")]
59impl<P: PacketPool> defmt::Format for L2capChannelWriter<'_, P> {
60    fn format(&self, f: defmt::Formatter<'_>) {
61        defmt::write!(f, "{}, ", self.index);
62        self.manager.print(self.index, f);
63    }
64}
65
66impl<P: PacketPool> Drop for L2capChannelWriter<'_, P> {
67    fn drop(&mut self) {
68        self.manager.dec_ref(self.index);
69    }
70}
71
72#[cfg(feature = "defmt")]
73impl<P: PacketPool> defmt::Format for L2capChannelReader<'_, P> {
74    fn format(&self, f: defmt::Formatter<'_>) {
75        defmt::write!(f, "{}, ", self.index);
76        self.manager.print(self.index, f);
77    }
78}
79
80impl<P: PacketPool> Drop for L2capChannelReader<'_, P> {
81    fn drop(&mut self) {
82        self.manager.dec_ref(self.index);
83    }
84}
85
86/// Configuration for an L2CAP channel.
87#[derive(Default)]
88pub struct L2capChannelConfig {
89    /// Size of Service Data Unit. Defaults to packet allocator MTU-6.
90    pub mtu: Option<u16>,
91    /// Frame size (1 frame == 1 credit). Defaults to packet allocator MTU-4.
92    pub mps: Option<u16>,
93    /// Flow control policy for connection oriented channels.
94    pub flow_policy: CreditFlowPolicy,
95    /// Initial credits for connection oriented channels.
96    pub initial_credits: Option<u16>,
97}
98
99impl<'d, P: PacketPool> L2capChannel<'d, P> {
100    pub(crate) fn new(index: ChannelIndex, manager: &'d ChannelManager<'d, P>) -> Self {
101        Self { index, manager }
102    }
103
104    /// Disconnect this channel.
105    pub fn disconnect(&mut self) {
106        self.manager.disconnect(self.index);
107    }
108
109    /// Get the PSM for this channel.
110    pub fn psm(&self) -> u16 {
111        self.manager.psm(self.index)
112    }
113
114    /// Send the provided buffer over this l2cap channel.
115    ///
116    /// The buffer must be equal to or smaller than the MTU agreed for the channel.
117    ///
118    /// If the channel has been closed or the channel id is not valid, an error is returned.
119    /// If there are no available credits to send, waits until more credits are available.
120    pub async fn send<T: Controller>(
121        &mut self,
122        stack: &Stack<'_, T, P>,
123        buf: &[u8],
124    ) -> Result<(), BleHostError<T::Error>> {
125        let mut p_buf = P::allocate().ok_or(Error::OutOfMemory)?;
126        stack
127            .host
128            .channels
129            .send(self.index, buf, p_buf.as_mut(), &stack.host)
130            .await
131    }
132
133    /// Send the provided buffer over this l2cap channel.
134    ///
135    /// The buffer must be equal to or smaller than the MTU agreed for the channel.
136    ///
137    /// If the channel has been closed or the channel id is not valid, an error is returned.
138    /// If there are no available credits to send, returns Error::Busy.
139    pub fn try_send<T: Controller + blocking::Controller>(
140        &mut self,
141        stack: &Stack<'_, T, P>,
142        buf: &[u8],
143    ) -> Result<(), BleHostError<T::Error>> {
144        let mut p_buf = P::allocate().ok_or(Error::OutOfMemory)?;
145        stack
146            .host
147            .channels
148            .try_send(self.index, buf, p_buf.as_mut(), &stack.host)
149    }
150
151    /// Receive data on this channel and copy it into the buffer.
152    ///
153    /// The length provided buffer slice must be equal or greater to the agreed MTU.
154    pub async fn receive<T: Controller>(
155        &mut self,
156        stack: &Stack<'_, T, P>,
157        buf: &mut [u8],
158    ) -> Result<usize, BleHostError<T::Error>> {
159        stack.host.channels.receive(self.index, buf, &stack.host).await
160    }
161
162    /// Receive the next SDU available on this channel.
163    ///
164    /// The length provided buffer slice must be equal or greater to the agreed MTU.
165    pub async fn receive_sdu<T: Controller>(
166        &mut self,
167        stack: &Stack<'_, T, P>,
168    ) -> Result<Sdu<P::Packet>, BleHostError<T::Error>> {
169        stack.host.channels.receive_sdu(self.index, &stack.host).await
170    }
171
172    /// Read metrics of the l2cap channel.
173    #[cfg(feature = "channel-metrics")]
174    pub fn metrics<F: FnOnce(&ChannelMetrics) -> R, R>(&self, f: F) -> R {
175        self.manager.metrics(self.index, f)
176    }
177
178    /// Await an incoming connection request matching the list of PSM.
179    pub async fn accept<T: Controller>(
180        stack: &'d Stack<'d, T, P>,
181        connection: &Connection<'_, P>,
182        psm: &[u16],
183        config: &L2capChannelConfig,
184    ) -> Result<Self, BleHostError<T::Error>> {
185        let handle = connection.handle();
186        stack.host.channels.accept(handle, psm, config, &stack.host).await
187    }
188
189    /// Create a new connection request with the provided PSM.
190    pub async fn create<T: Controller>(
191        stack: &'d Stack<'d, T, P>,
192        connection: &Connection<'_, P>,
193        psm: u16,
194        config: &L2capChannelConfig,
195    ) -> Result<Self, BleHostError<T::Error>> {
196        stack
197            .host
198            .channels
199            .create(connection.handle(), psm, config, &stack.host)
200            .await
201    }
202
203    /// Split the channel into a writer and reader for concurrently
204    /// writing to/reading from the channel.
205    pub fn split(self) -> (L2capChannelWriter<'d, P>, L2capChannelReader<'d, P>) {
206        self.manager.inc_ref(self.index);
207        self.manager.inc_ref(self.index);
208        (
209            L2capChannelWriter {
210                index: self.index,
211                manager: self.manager,
212            },
213            L2capChannelReader {
214                index: self.index,
215                manager: self.manager,
216            },
217        )
218    }
219
220    /// Merge writer and reader into a single channel again.
221    ///
222    /// This function will panic if the channels are not referring to the same channel id.
223    pub fn merge(writer: L2capChannelWriter<'d, P>, reader: L2capChannelReader<'d, P>) -> Self {
224        // A channel will not be reused unless the refcount is 0, so the index could
225        // never be stale.
226        assert_eq!(writer.index, reader.index);
227
228        let manager = writer.manager;
229        let index = writer.index;
230        manager.inc_ref(index);
231
232        Self { index, manager }
233    }
234}
235
236impl<'d, P: PacketPool> L2capChannelReader<'d, P> {
237    /// Disconnect this channel.
238    pub fn disconnect(&mut self) {
239        self.manager.disconnect(self.index);
240    }
241
242    /// Receive data on this channel and copy it into the buffer.
243    ///
244    /// The length provided buffer slice must be equal or greater to the agreed MTU.
245    pub async fn receive<T: Controller>(
246        &mut self,
247        stack: &Stack<'_, T, P>,
248        buf: &mut [u8],
249    ) -> Result<usize, BleHostError<T::Error>> {
250        stack.host.channels.receive(self.index, buf, &stack.host).await
251    }
252
253    /// Receive the next SDU available on this channel.
254    ///
255    /// The length provided buffer slice must be equal or greater to the agreed MTU.
256    pub async fn receive_sdu<T: Controller>(
257        &mut self,
258        stack: &Stack<'_, T, P>,
259    ) -> Result<Sdu<P::Packet>, BleHostError<T::Error>> {
260        stack.host.channels.receive_sdu(self.index, &stack.host).await
261    }
262
263    /// Read metrics of the l2cap channel.
264    #[cfg(feature = "channel-metrics")]
265    pub fn metrics<F: FnOnce(&ChannelMetrics) -> R, R>(&self, f: F) -> R {
266        self.manager.metrics(self.index, f)
267    }
268
269    /// Create a channel reference for the l2cap channel.
270    pub fn channel_ref(&mut self) -> L2capChannelRef<'d, P> {
271        self.manager.inc_ref(self.index);
272        L2capChannelRef {
273            index: self.index,
274            manager: self.manager,
275        }
276    }
277}
278
279impl<'d, P: PacketPool> L2capChannelRef<'d, P> {
280    #[cfg(feature = "channel-metrics")]
281    /// Read metrics of the l2cap channel.
282    pub fn metrics<F: FnOnce(&ChannelMetrics) -> R, R>(&self, f: F) -> R {
283        self.manager.metrics(self.index, f)
284    }
285}
286
287impl<'d, P: PacketPool> L2capChannelWriter<'d, P> {
288    /// Disconnect this channel.
289    pub fn disconnect(&mut self) {
290        self.manager.disconnect(self.index);
291    }
292
293    /// Send the provided buffer over this l2cap channel.
294    ///
295    /// The buffer must be equal to or smaller than the MTU agreed for the channel.
296    ///
297    /// If the channel has been closed or the channel id is not valid, an error is returned.
298    /// If there are no available credits to send, waits until more credits are available.
299    pub async fn send<T: Controller>(
300        &mut self,
301        stack: &Stack<'_, T, P>,
302        buf: &[u8],
303    ) -> Result<(), BleHostError<T::Error>> {
304        let mut p_buf = P::allocate().ok_or(Error::OutOfMemory)?;
305        stack
306            .host
307            .channels
308            .send(self.index, buf, p_buf.as_mut(), &stack.host)
309            .await
310    }
311
312    /// Send the provided buffer over this l2cap channel.
313    ///
314    /// The buffer must be equal to or smaller than the MTU agreed for the channel.
315    ///
316    /// If the channel has been closed or the channel id is not valid, an error is returned.
317    /// If there are no available credits to send, returns Error::Busy.
318    pub fn try_send<T: Controller + blocking::Controller>(
319        &mut self,
320        stack: &Stack<'_, T, P>,
321        buf: &[u8],
322    ) -> Result<(), BleHostError<T::Error>> {
323        let mut p_buf = P::allocate().ok_or(Error::OutOfMemory)?;
324        stack
325            .host
326            .channels
327            .try_send(self.index, buf, p_buf.as_mut(), &stack.host)
328    }
329
330    /// Read metrics of the l2cap channel.
331    #[cfg(feature = "channel-metrics")]
332    pub fn metrics<F: FnOnce(&ChannelMetrics) -> R, R>(&self, f: F) -> R {
333        self.manager.metrics(self.index, f)
334    }
335
336    /// Create a channel reference for the l2cap channel.
337    pub fn channel_ref(&mut self) -> L2capChannelRef<'d, P> {
338        self.manager.inc_ref(self.index);
339        L2capChannelRef {
340            index: self.index,
341            manager: self.manager,
342        }
343    }
344}