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}