1use bt_hci::{FixedSizeValue, WriteHci};
2
3pub(crate) const L2CAP_CID_ATT: u16 = 0x0004;
4pub(crate) const L2CAP_CID_LE_U_SIGNAL: u16 = 0x0005;
5pub(crate) const L2CAP_CID_LE_U_SECURITY_MANAGER: u16 = 0x0006;
6pub(crate) const L2CAP_CID_DYN_START: u16 = 0x0040;
7
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9#[derive(Debug, Clone, Copy)]
10#[repr(C)]
11pub struct L2capHeader {
12 pub length: u16,
13 pub channel: u16,
14}
15
16unsafe impl FixedSizeValue for L2capHeader {
17 fn is_valid(data: &[u8]) -> bool {
18 true
19 }
20}
21
22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23#[repr(C)]
24#[derive(Debug, Clone, Copy)]
25pub struct L2capSignalHeader {
26 pub code: L2capSignalCode,
27 pub identifier: u8,
28 pub length: u16,
29}
30
31unsafe impl FixedSizeValue for L2capSignalHeader {
32 fn is_valid(data: &[u8]) -> bool {
33 true
34 }
35}
36
37#[cfg(not(feature = "defmt"))]
38pub trait L2capSignal: WriteHci + FixedSizeValue + core::fmt::Debug {
39 fn channel() -> u16 {
40 L2CAP_CID_LE_U_SIGNAL
41 }
42 fn code() -> L2capSignalCode;
43}
44
45#[cfg(feature = "defmt")]
46pub trait L2capSignal: WriteHci + FixedSizeValue + defmt::Format {
47 fn channel() -> u16 {
48 L2CAP_CID_LE_U_SIGNAL
49 }
50 fn code() -> L2capSignalCode;
51}
52
53#[derive(Clone, Copy, PartialEq)]
54#[repr(transparent)]
55pub struct L2capSignalCode(pub u8);
56
57unsafe impl FixedSizeValue for L2capSignalCode {
58 fn is_valid(_data: &[u8]) -> bool {
59 true
60 }
61}
62
63impl core::fmt::Debug for L2capSignalCode {
64 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
65 match *self {
66 Self::COMMAND_REJECT_RES => write!(f, "CommandRejectRes"),
67 Self::CONNECTION_REQ => write!(f, "ConnectionReq"),
68 Self::CONNECTION_RES => write!(f, "ConnectionRes"),
69 Self::CONFIGURATION_REQ => write!(f, "ConfigurationReq"),
70 Self::CONFIGURATION_RES => write!(f, "ConfigurationRes"),
71 Self::DISCONNECTION_REQ => write!(f, "DisconnectionReq"),
72 Self::DISCONNECTION_RES => write!(f, "DisconnectionRes"),
73 Self::ECHO_REQ => write!(f, "EchoReq"),
74 Self::ECHO_RES => write!(f, "EchoRes"),
75 Self::INFORMATION_REQ => write!(f, "InformationReq"),
76 Self::INFORMATION_RES => write!(f, "InformationRes"),
77 Self::CONN_PARAM_UPDATE_REQ => write!(f, "ConnParamUpdateReq"),
78 Self::CONN_PARAM_UPDATE_RES => write!(f, "ConnParamUpdateRes"),
79 Self::LE_CREDIT_CONN_REQ => write!(f, "LeCreditConnReq"),
80 Self::LE_CREDIT_CONN_RES => write!(f, "LeCreditConnRes"),
81 Self::LE_CREDIT_FLOW_IND => write!(f, "LeCreditFlowInd"),
82 Self::CREDIT_CONN_REQ => write!(f, "CreditConnReq"),
83 Self::CREDIT_CONN_RES => write!(f, "CreditConnRes"),
84 Self::CREDIT_CONN_RECONFIG_REQ => write!(f, "CreditConnReconfigReq"),
85 Self::CREDIT_CONN_RECONFIG_RES => write!(f, "CreditConnReconfigRes"),
86 _ => write!(f, "Unknown(0x{:02x})", self.0),
87 }
88 }
89}
90
91#[cfg(feature = "defmt")]
92impl defmt::Format for L2capSignalCode {
93 fn format(&self, f: defmt::Formatter<'_>) {
94 match *self {
95 Self::COMMAND_REJECT_RES => defmt::write!(f, "CommandRejectRes"),
96 Self::CONNECTION_REQ => defmt::write!(f, "ConnectionReq"),
97 Self::CONNECTION_RES => defmt::write!(f, "ConnectionRes"),
98 Self::CONFIGURATION_REQ => defmt::write!(f, "ConfigurationReq"),
99 Self::CONFIGURATION_RES => defmt::write!(f, "ConfigurationRes"),
100 Self::DISCONNECTION_REQ => defmt::write!(f, "DisconnectionReq"),
101 Self::DISCONNECTION_RES => defmt::write!(f, "DisconnectionRes"),
102 Self::ECHO_REQ => defmt::write!(f, "EchoReq"),
103 Self::ECHO_RES => defmt::write!(f, "EchoRes"),
104 Self::INFORMATION_REQ => defmt::write!(f, "InformationReq"),
105 Self::INFORMATION_RES => defmt::write!(f, "InformationRes"),
106 Self::CONN_PARAM_UPDATE_REQ => defmt::write!(f, "ConnParamUpdateReq"),
107 Self::CONN_PARAM_UPDATE_RES => defmt::write!(f, "ConnParamUpdateRes"),
108 Self::LE_CREDIT_CONN_REQ => defmt::write!(f, "LeCreditConnReq"),
109 Self::LE_CREDIT_CONN_RES => defmt::write!(f, "LeCreditConnRes"),
110 Self::LE_CREDIT_FLOW_IND => defmt::write!(f, "LeCreditFlowInd"),
111 Self::CREDIT_CONN_REQ => defmt::write!(f, "CreditConnReq"),
112 Self::CREDIT_CONN_RES => defmt::write!(f, "CreditConnRes"),
113 Self::CREDIT_CONN_RECONFIG_REQ => defmt::write!(f, "CreditConnReconfigReq"),
114 Self::CREDIT_CONN_RECONFIG_RES => defmt::write!(f, "CreditConnReconfigRes"),
115 _ => defmt::write!(f, "Unknown(0x{:02x})", self.0),
116 }
117 }
118}
119
120impl From<u8> for L2capSignalCode {
121 fn from(val: u8) -> Self {
122 Self(val)
123 }
124}
125
126#[allow(non_upper_case_globals)]
127impl L2capSignalCode {
128 pub const COMMAND_REJECT_RES: Self = Self(0x01);
129 pub const CONNECTION_REQ: Self = Self(0x02);
130 pub const CONNECTION_RES: Self = Self(0x03);
131 pub const CONFIGURATION_REQ: Self = Self(0x04);
132 pub const CONFIGURATION_RES: Self = Self(0x05);
133 pub const DISCONNECTION_REQ: Self = Self(0x06);
134 pub const DISCONNECTION_RES: Self = Self(0x07);
135 pub const ECHO_REQ: Self = Self(0x08);
136 pub const ECHO_RES: Self = Self(0x09);
137 pub const INFORMATION_REQ: Self = Self(0x0A);
138 pub const INFORMATION_RES: Self = Self(0x0B);
139 pub const CONN_PARAM_UPDATE_REQ: Self = Self(0x12);
140 pub const CONN_PARAM_UPDATE_RES: Self = Self(0x13);
141 pub const LE_CREDIT_CONN_REQ: Self = Self(0x14);
142 pub const LE_CREDIT_CONN_RES: Self = Self(0x15);
143 pub const LE_CREDIT_FLOW_IND: Self = Self(0x16);
144 pub const CREDIT_CONN_REQ: Self = Self(0x17);
145 pub const CREDIT_CONN_RES: Self = Self(0x18);
146 pub const CREDIT_CONN_RECONFIG_REQ: Self = Self(0x19);
147 pub const CREDIT_CONN_RECONFIG_RES: Self = Self(0x1A);
148}
149
150#[cfg_attr(feature = "defmt", derive(defmt::Format))]
151#[repr(C)]
152#[derive(Debug, Clone, Copy)]
153pub struct LeCreditConnReq {
154 pub spsm: u16,
155 pub scid: u16,
156 pub mtu: u16,
157 pub mps: u16,
158 pub credits: u16,
159}
160
161unsafe impl FixedSizeValue for LeCreditConnReq {
162 fn is_valid(data: &[u8]) -> bool {
163 true
164 }
165}
166
167impl L2capSignal for LeCreditConnReq {
168 fn code() -> L2capSignalCode {
169 L2capSignalCode::LE_CREDIT_CONN_REQ
170 }
171}
172
173#[cfg_attr(feature = "defmt", derive(defmt::Format))]
174#[derive(Debug, Clone, Copy, PartialEq, Eq)]
175#[repr(u16)]
176pub enum LeCreditConnResultCode {
178 Success = 0x0000,
180 SpsmNotSupported = 0x0002,
182 NoResources = 0x0004,
184 InsufficientAuthentication = 0x0005,
186 InsufficientAuthorization = 0x0006,
188 EncryptionKeyTooShort = 0x0007,
190 InsufficientEncryption = 0x0008,
192 InvalidSourceId = 0x0009,
194 ScidAlreadyAllocated = 0x000A,
196 UnacceptableParameters = 0x000B,
198}
199
200#[cfg_attr(feature = "defmt", derive(defmt::Format))]
201#[repr(C)]
202#[derive(Debug, Clone, Copy)]
203pub struct LeCreditConnRes {
204 pub dcid: u16,
205 pub mtu: u16,
206 pub mps: u16,
207 pub credits: u16,
208 pub result: LeCreditConnResultCode,
209}
210
211impl LeCreditConnRes {
212 pub const fn reject(result: LeCreditConnResultCode) -> Self {
213 Self {
214 dcid: 0,
215 mtu: 0,
216 mps: 0,
217 credits: 0,
218 result,
219 }
220 }
221}
222
223impl L2capSignal for LeCreditConnRes {
224 fn code() -> L2capSignalCode {
225 L2capSignalCode::LE_CREDIT_CONN_RES
226 }
227}
228
229unsafe impl FixedSizeValue for LeCreditConnRes {
230 fn is_valid(data: &[u8]) -> bool {
231 true
232 }
233}
234
235#[repr(C)]
236#[derive(Debug, Clone, Copy)]
237#[cfg_attr(feature = "defmt", derive(defmt::Format))]
238pub struct LeCreditFlowInd {
239 pub cid: u16,
240 pub credits: u16,
241}
242
243unsafe impl FixedSizeValue for LeCreditFlowInd {
244 fn is_valid(data: &[u8]) -> bool {
245 true
246 }
247}
248
249impl L2capSignal for LeCreditFlowInd {
250 fn code() -> L2capSignalCode {
251 L2capSignalCode::LE_CREDIT_FLOW_IND
252 }
253}
254
255#[cfg_attr(feature = "defmt", derive(defmt::Format))]
256#[repr(C)]
257#[derive(Debug, Clone, Copy)]
258pub struct CommandRejectRes {
259 pub reason: u16,
260 }
262
263unsafe impl FixedSizeValue for CommandRejectRes {
264 fn is_valid(data: &[u8]) -> bool {
265 true
266 }
267}
268
269impl L2capSignal for CommandRejectRes {
270 fn code() -> L2capSignalCode {
271 L2capSignalCode::COMMAND_REJECT_RES
272 }
273}
274
275#[cfg_attr(feature = "defmt", derive(defmt::Format))]
276#[repr(C)]
277#[derive(Debug, Clone, Copy)]
278pub struct DisconnectionReq {
279 pub dcid: u16,
280 pub scid: u16,
281}
282
283unsafe impl FixedSizeValue for DisconnectionReq {
284 fn is_valid(data: &[u8]) -> bool {
285 true
286 }
287}
288
289impl L2capSignal for DisconnectionReq {
290 fn code() -> L2capSignalCode {
291 L2capSignalCode::DISCONNECTION_REQ
292 }
293}
294
295#[cfg_attr(feature = "defmt", derive(defmt::Format))]
296#[repr(C)]
297#[derive(Debug, Clone, Copy)]
298pub struct DisconnectionRes {
299 pub dcid: u16,
300 pub scid: u16,
301}
302
303unsafe impl FixedSizeValue for DisconnectionRes {
304 fn is_valid(data: &[u8]) -> bool {
305 true
306 }
307}
308
309impl L2capSignal for DisconnectionRes {
310 fn code() -> L2capSignalCode {
311 L2capSignalCode::DISCONNECTION_RES
312 }
313}
314
315#[cfg_attr(feature = "defmt", derive(defmt::Format))]
316#[repr(C)]
317#[derive(Debug, Clone, Copy)]
318pub struct ConnParamUpdateReq {
319 pub interval_min: u16,
320 pub interval_max: u16,
321 pub latency: u16,
322 pub timeout: u16,
323}
324
325unsafe impl FixedSizeValue for ConnParamUpdateReq {
326 fn is_valid(data: &[u8]) -> bool {
327 true
328 }
329}
330
331impl L2capSignal for ConnParamUpdateReq {
332 fn code() -> L2capSignalCode {
333 L2capSignalCode::CONN_PARAM_UPDATE_REQ
334 }
335}
336
337#[cfg_attr(feature = "defmt", derive(defmt::Format))]
338#[repr(C)]
339#[derive(Debug, Clone, Copy)]
340pub struct ConnParamUpdateRes {
341 pub result: u16,
342}
343
344unsafe impl FixedSizeValue for ConnParamUpdateRes {
345 fn is_valid(data: &[u8]) -> bool {
346 true
347 }
348}
349
350impl L2capSignal for ConnParamUpdateRes {
351 fn code() -> L2capSignalCode {
352 L2capSignalCode::CONN_PARAM_UPDATE_RES
353 }
354}