stm32wb_hci/vendor/command/
l2cap.rs

1//! L2Cap-specific commands and types needed for those commands.
2
3extern crate byteorder;
4
5use crate::{
6    types::{ConnectionInterval, ExpectedConnectionLength},
7    ConnectionHandle, Controller,
8};
9use byteorder::{ByteOrder, LittleEndian};
10
11/// L2Cap-specific commands.
12pub trait L2capCommands {
13    /// Send an L2CAP connection parameter update request from the peripheral to the central
14    /// device.
15    ///
16    /// # Errors
17    ///
18    /// - Underlying communication errors.
19    ///
20    /// # Generated events
21    ///
22    /// A [command status](crate::event::Event::CommandStatus) event on the receipt of the command and
23    /// an [L2CAP Connection Update Response](crate::vendor::event::L2CapConnectionUpdateResponse) event when the master
24    /// responds to the request (accepts or rejects).
25    async fn connection_parameter_update_request(
26        &mut self,
27        params: &ConnectionParameterUpdateRequest,
28    );
29
30    /// This command should be sent in response to the
31    /// [`L2CapConnectionUpdateResponse`](crate::vendor::event::L2CapConnectionUpdateResponse)
32    /// event from the controller. The accept parameter has to be set to true if the connection
33    /// parameters given in the event are acceptable.
34    ///
35    /// # Errors
36    ///
37    /// Only underlying communication errors are reported.
38    ///
39    /// # Generated events
40    ///
41    /// A [Command Complete](crate::event::command::CommandComplete) event is generated.
42    async fn connection_parameter_update_response(
43        &mut self,
44        params: &ConnectionParameterUpdateResponse,
45    );
46
47    /// This command sends a Credit-Based Connection Request packet to the specified connection.
48    ///
49    /// See Bluetooth Core specification Vol.3 Part A.
50    async fn coc_connect(&mut self, params: &L2CapCocConnect);
51
52    /// This command sends a Credit-Based Connection Response packet. It must be used upon receipt
53    /// of a connection request though [L2CAP COC Connection](crate::vendor::event::VendorEvent::L2CapCocConnect)
54    /// event.
55    ///
56    /// See Bluetooth Core specification Vol.3 Part A.
57    async fn coc_connect_confirm(&mut self, params: &L2CapCocConnectConfirm);
58
59    /// This command sends a Credit-Based Reconfigure Request packet on the specified connection.
60    ///
61    /// See Bluetooth Core specification Vol.3 Part A.
62    async fn coc_reconfig(&mut self, params: &L2CapCocReconfig);
63
64    /// This command sends a Credit-Based Reconfigure Response packet. It must be use upon receipt
65    /// of a Credit-Based Reconfigure Request through
66    /// [L2CAP COC Reconfigure](crate::vendor::event::VendorEvent::L2CapCocReconfig) event.
67    ///
68    ///  See Bluetooth Core specification Vol.3 Part A.
69    async fn coc_reconfig_confirm(&mut self, params: &L2CapCocReconfigConfirm);
70
71    /// This command sends a Disconnection Request signaling packet on the specified connection-oriented
72    /// channel.
73    ///
74    /// See Bluetooth Core specification Vol.3 Part A.
75    ///
76    /// # Generated events
77    /// A [L2CAP COC Disconnection](crate::vendor::event::VendorEvent::L2CapCocDisconnect) event is
78    /// received when the disconnection of the channel is effective.
79    async fn coc_disconnect(&mut self, channel_index: u8);
80
81    /// This command sends a Flow Control Credit signaling packet on the specified connection-oriented
82    /// channel.
83    ///
84    /// See Bluetooth Core specification Vol.3 Part A.
85    async fn coc_flow_control(&mut self, params: &L2CapCocFlowControl);
86
87    /// This command sends a K-frame packet on the specified connection-oriented channel.
88    ///
89    /// See Bluetooth Core specification Vol.3 Part A.
90    ///
91    /// # Note
92    /// for the first K-frame of the SDU, the Information data shall contain
93    /// the L2CAP SDU Length coded on two octets followed by the K-frame information
94    /// payload. For the next K-frames of the SDU, the Information data shall only
95    /// contain the K-frame information payload.
96    /// The Length value must not exceed (BLE_CMD_MAX_PARAM_LEN - 3) i.e. 252 for
97    /// BLE_CMD_MAX_PARAM_LEN default value.
98    async fn coc_tx_data(&mut self, params: &L2CapCocTxData);
99}
100
101impl<T: Controller> L2capCommands for T {
102    impl_params!(
103        connection_parameter_update_request,
104        ConnectionParameterUpdateRequest,
105        crate::vendor::opcode::L2CAP_CONN_PARAM_UPDATE_REQ
106    );
107
108    impl_params!(
109        connection_parameter_update_response,
110        ConnectionParameterUpdateResponse,
111        crate::vendor::opcode::L2CAP_CONN_PARAM_UPDATE_RESP
112    );
113
114    impl_params!(
115        coc_connect,
116        L2CapCocConnect,
117        crate::vendor::opcode::L2CAP_COC_CONNECT
118    );
119
120    impl_variable_length_params!(
121        coc_connect_confirm,
122        L2CapCocConnectConfirm,
123        crate::vendor::opcode::L2CAP_COC_CONNECT_CONFIRM
124    );
125
126    impl_variable_length_params!(
127        coc_reconfig,
128        L2CapCocReconfig,
129        crate::vendor::opcode::L2CAP_COC_RECONFIG
130    );
131
132    impl_params!(
133        coc_reconfig_confirm,
134        L2CapCocReconfigConfirm,
135        crate::vendor::opcode::L2CAP_COC_RECONFIG_CONFIRM
136    );
137
138    async fn coc_disconnect(&mut self, channel_index: u8) {
139        self.controller_write(
140            crate::vendor::opcode::L2CAP_COC_DISCONNECT,
141            &[channel_index],
142        )
143        .await
144    }
145
146    impl_params!(
147        coc_flow_control,
148        L2CapCocFlowControl,
149        crate::vendor::opcode::L2CAP_COC_FLOW_CONTROL
150    );
151
152    impl_variable_length_params!(
153        coc_tx_data,
154        L2CapCocTxData,
155        crate::vendor::opcode::L2CAP_COC_TX_DATA
156    );
157}
158
159/// Parameters for the
160/// [`connection_parameter_update_request`](L2capCommands::connection_parameter_update_request)
161/// command.
162pub struct ConnectionParameterUpdateRequest {
163    /// Connection handle of the link which the connection parameter update request has to be sent.
164    pub conn_handle: crate::ConnectionHandle,
165
166    /// Defines the range of the connection interval.
167    pub conn_interval: ConnectionInterval,
168}
169
170impl ConnectionParameterUpdateRequest {
171    const LENGTH: usize = 10;
172
173    fn copy_into_slice(&self, bytes: &mut [u8]) {
174        assert_eq!(bytes.len(), Self::LENGTH);
175
176        LittleEndian::write_u16(&mut bytes[0..], self.conn_handle.0);
177        self.conn_interval.copy_into_slice(&mut bytes[2..10]);
178    }
179}
180
181/// Parameters for the
182/// [`connection_parameter_update_response`](L2capCommands::connection_parameter_update_response)
183/// command.
184pub struct ConnectionParameterUpdateResponse {
185    /// [Connection handle](crate::vendor::event::L2CapConnectionUpdateRequest::conn_handle) received in the
186    /// [`L2CapConnectionUpdateRequest`](crate::vendor::event::L2CapConnectionUpdateRequest)
187    /// event.
188    pub conn_handle: crate::ConnectionHandle,
189
190    /// [Connection interval](crate::vendor::event::L2CapConnectionUpdateRequest::conn_interval) received in
191    /// the
192    /// [`L2CapConnectionUpdateRequest`](crate::vendor::event::L2CapConnectionUpdateRequest)
193    /// event.
194    pub conn_interval: ConnectionInterval,
195
196    /// Expected length of connection event needed for this connection.
197    pub expected_connection_length_range: ExpectedConnectionLength,
198
199    /// [Identifier](crate::vendor::event::L2CapConnectionUpdateRequest::identifier) received in the
200    /// [`L2CapConnectionUpdateRequest`](crate::vendor::event::L2CapConnectionUpdateRequest)
201    /// event.
202    pub identifier: u8,
203
204    /// True if the parameters from the
205    /// [event](crate::vendor::event::L2CapConnectionUpdateRequest) are acceptable.
206    pub accepted: bool,
207}
208
209impl ConnectionParameterUpdateResponse {
210    const LENGTH: usize = 16;
211
212    fn copy_into_slice(&self, bytes: &mut [u8]) {
213        assert_eq!(bytes.len(), Self::LENGTH);
214
215        LittleEndian::write_u16(&mut bytes[0..], self.conn_handle.0);
216        self.conn_interval.copy_into_slice(&mut bytes[2..10]);
217        self.expected_connection_length_range
218            .copy_into_slice(&mut bytes[10..14]);
219        bytes[14] = self.identifier;
220        bytes[15] = self.accepted as u8;
221    }
222}
223
224#[derive(Debug, Clone, Copy)]
225#[cfg_attr(feature = "defmt", derive(defmt::Format))]
226/// This event is generated when receiving a valid Credit Based Connection
227/// Request packet.
228///
229/// See Bluetooth spec. v.5.4 [Vol 3, Part A].
230pub struct L2CapCocConnect {
231    /// handle of the connection where this event occured.
232    pub conn_handle: ConnectionHandle,
233    /// Simplified Protocol/Service Multiplexer
234    ///
235    /// Values:
236    /// - 0x0000 .. 0x00FF
237    pub spsm: u16,
238    /// Maximum Transmission Unit
239    ///
240    /// Values:
241    /// - 23 .. 65535
242    pub mtu: u16,
243    /// Maximum Payload Size (in octets)
244    ///
245    /// Values:
246    /// - 23 .. 248
247    pub mps: u16,
248    /// Number of K-frames that can be received on the created channel(s) by
249    /// the L2CAP layer entity sending this packet.
250    ///
251    /// Values:
252    /// - 0 .. 65535
253    pub initial_credits: u16,
254    /// Number of channels to be created. If this parameter is
255    /// set to 0, it requests the creation of one LE credit based connection-
256    /// oriented channel. Otherwise, it requests the creation of one or more
257    /// enhanced credit based connection-oriented channels.
258    ///
259    /// Values:
260    /// - 0 .. 5
261    pub channel_number: u8,
262}
263
264impl L2CapCocConnect {
265    const LENGTH: usize = 11;
266
267    fn copy_into_slice(&self, bytes: &mut [u8]) {
268        assert_eq!(bytes.len(), Self::LENGTH);
269
270        LittleEndian::write_u16(&mut bytes[0..], self.conn_handle.0);
271        LittleEndian::write_u16(&mut bytes[2..], self.spsm);
272        LittleEndian::write_u16(&mut bytes[4..], self.mtu);
273        LittleEndian::write_u16(&mut bytes[6..], self.mps);
274        LittleEndian::write_u16(&mut bytes[8..], self.initial_credits);
275        bytes[10] = self.channel_number;
276    }
277}
278
279#[derive(Debug, Clone, Copy)]
280#[cfg_attr(feature = "defmt", derive(defmt::Format))]
281/// This event is generated when receiving a valid Credit Based Connection Response packet.
282///
283/// See Bluetooth spec. v.5.4 [Vol 3, Part A].
284pub struct L2CapCocConnectConfirm {
285    /// handle of the connection where this event occured.
286    pub conn_handle: ConnectionHandle,
287    /// Maximum Transmission Unit
288    ///
289    /// Values:
290    /// - 23 .. 65535
291    pub mtu: u16,
292    /// Maximum Payload Size (in octets)
293    ///
294    /// Values:
295    /// - 23 .. 248
296    pub mps: u16,
297    /// Number of K-frames that can be received on the created channel(s) by
298    /// the L2CAP layer entity sending this packet.
299    ///
300    /// Values:
301    /// - 0 .. 65535
302    pub initial_credits: u16,
303    /// This parameter indicates the outcome of the request. A value of 0x0000
304    /// indicates success while a non zero value indicates the request is refused
305    ///
306    /// Values:
307    /// - 0x0000 .. 0x000C
308    pub result: u16,
309    /// Number of channels to be created. If this parameter is
310    /// set to 0, it requests the creation of one LE credit based connection-
311    /// oriented channel. Otherwise, it requests the creation of one or more
312    /// enhanced credit based connection-oriented channels.
313    ///
314    /// Values:
315    /// - 0 .. 5
316    pub channel_number: u8,
317    /// List of channel indexes for which the primitives apply.
318    pub channel_index_list: [u8; 246],
319}
320
321impl L2CapCocConnectConfirm {
322    const MAX_LENGTH: usize = 258;
323
324    fn copy_into_slice(&self, bytes: &mut [u8]) {
325        assert!(bytes.len() >= Self::MAX_LENGTH);
326
327        LittleEndian::write_u16(&mut bytes[0..], self.conn_handle.0);
328        LittleEndian::write_u16(&mut bytes[2..], self.mtu);
329        LittleEndian::write_u16(&mut bytes[4..], self.mps);
330        LittleEndian::write_u16(&mut bytes[6..], self.initial_credits);
331        LittleEndian::write_u16(&mut bytes[8..], self.result);
332        bytes[10] = self.channel_number;
333        bytes[11..].copy_from_slice(&self.channel_index_list);
334    }
335}
336
337#[derive(Debug, Clone, Copy)]
338#[cfg_attr(feature = "defmt", derive(defmt::Format))]
339/// This event is generated when receiving a valid Credit Based Reconfigure Request packet.
340///
341/// See Bluetooth spec. v.5.4 [Vol 3, Part A].
342pub struct L2CapCocReconfig {
343    /// handle of the connection where this event occured.
344    pub conn_handle: ConnectionHandle,
345    /// Maximum Transmission Unit
346    ///
347    /// Values:
348    /// - 23 .. 65535
349    pub mtu: u16,
350    /// Maximum Payload Size (in octets)
351    ///
352    /// Values:
353    /// - 23 .. 248
354    pub mps: u16,
355    /// Number of channels to be created. If this parameter is
356    /// set to 0, it requests the creation of one LE credit based connection-
357    /// oriented channel. Otherwise, it requests the creation of one or more
358    /// enhanced credit based connection-oriented channels.
359    ///
360    /// Values:
361    /// - 0 .. 5
362    pub channel_number: u8,
363    /// List of channel indexes for which the primitives apply.
364    pub channel_index_list: [u8; 246],
365}
366
367impl L2CapCocReconfig {
368    const MAX_LENGTH: usize = 254;
369
370    fn copy_into_slice(&self, bytes: &mut [u8]) {
371        assert!(bytes.len() >= Self::MAX_LENGTH);
372
373        LittleEndian::write_u16(&mut bytes[0..], self.conn_handle.0);
374        LittleEndian::write_u16(&mut bytes[2..], self.mtu);
375        LittleEndian::write_u16(&mut bytes[4..], self.mps);
376        bytes[6] = self.channel_number;
377        bytes[7..].copy_from_slice(&self.channel_index_list);
378    }
379}
380
381#[derive(Debug, Clone, Copy)]
382#[cfg_attr(feature = "defmt", derive(defmt::Format))]
383/// This event is generated when receiving a valid Credit Based Reconfigure Response packet.
384///
385/// See Bluetooth spec. v.5.4 [Vol 3, Part A].
386pub struct L2CapCocReconfigConfirm {
387    /// handle of the connection where this event occured.
388    pub conn_handle: ConnectionHandle,
389    /// This parameter indicates the outcome of the request. A value of 0x0000
390    /// indicates success while a non zero value indicates the request is refused
391    ///
392    /// Values:
393    /// - 0x0000 .. 0x000C
394    pub result: u16,
395}
396
397impl L2CapCocReconfigConfirm {
398    const LENGTH: usize = 4;
399
400    fn copy_into_slice(&self, bytes: &mut [u8]) {
401        assert_eq!(bytes.len(), Self::LENGTH);
402
403        LittleEndian::write_u16(&mut bytes[0..], self.conn_handle.0);
404        LittleEndian::write_u16(&mut bytes[2..], self.result);
405    }
406}
407
408#[derive(Debug, Clone, Copy)]
409#[cfg_attr(feature = "defmt", derive(defmt::Format))]
410/// This event is generated when receiving a valid Flow Control Credit signaling packet.
411///
412/// See Bluetooth spec. v.5.4 [Vol 3, Part A].
413pub struct L2CapCocFlowControl {
414    /// Index of the connection-oriented channel for which the primitive applies.
415    pub channel_index: u8,
416    /// Number of credits the receiving device can increment, corresponding to the
417    /// number of K-frames that can be sent to the peer device sending Flow Control
418    /// Credit packet.
419    ///
420    /// Values:
421    /// - 0 .. 65535
422    pub credits: u16,
423}
424
425impl L2CapCocFlowControl {
426    const LENGTH: usize = 3;
427
428    fn copy_into_slice(&self, bytes: &mut [u8]) {
429        assert_eq!(bytes.len(), Self::LENGTH);
430
431        bytes[0] = self.channel_index;
432        LittleEndian::write_u16(&mut bytes[1..], self.credits);
433    }
434}
435
436#[derive(Debug, Clone, Copy)]
437#[cfg_attr(feature = "defmt", derive(defmt::Format))]
438/// Parameter for the [coc_tx_data](L2capCommands::coc_tx_data) command
439pub struct L2CapCocTxData {
440    pub channel_index: u8,
441    pub length: u16,
442    pub data: [u8; 252],
443}
444
445impl L2CapCocTxData {
446    const MAX_LENGTH: usize = 256;
447
448    fn copy_into_slice(&self, bytes: &mut [u8]) {
449        assert!(bytes.len() >= Self::MAX_LENGTH);
450
451        bytes[0] = self.channel_index;
452        LittleEndian::write_u16(&mut bytes[1..], self.length);
453        bytes[3..].copy_from_slice(&self.data);
454    }
455}