1use crate::{AsHciBytes, ByteAlignedValue, FixedSizeValue, FromHciBytes, FromHciBytesError, WriteHci};
4
5mod classic;
6mod cmd_mask;
7mod event_masks;
8mod feature_masks;
9mod le;
10mod macros;
11mod primitives;
12mod status;
13
14pub use classic::*;
15pub use cmd_mask::*;
16pub use event_masks::*;
17pub use feature_masks::*;
18pub use le::*;
19pub(crate) use macros::{param, param_slice};
20pub use status::*;
21
22#[repr(transparent)]
24#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub struct RemainingBytes<'a>(&'a [u8]);
27
28impl core::ops::Deref for RemainingBytes<'_> {
29 type Target = [u8];
30
31 fn deref(&self) -> &Self::Target {
32 self.0
33 }
34}
35
36impl WriteHci for RemainingBytes<'_> {
37 #[inline(always)]
38 fn size(&self) -> usize {
39 self.0.len()
40 }
41
42 #[inline(always)]
43 fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
44 writer.write_all(self.0)
45 }
46
47 #[inline(always)]
48 async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
49 writer.write_all(self.0).await
50 }
51}
52
53impl AsHciBytes for RemainingBytes<'_> {
54 fn as_hci_bytes(&self) -> &[u8] {
55 self.0
56 }
57}
58
59impl<'a> FromHciBytes<'a> for RemainingBytes<'a> {
60 fn from_hci_bytes(data: &'a [u8]) -> Result<(Self, &'a [u8]), FromHciBytesError> {
61 Ok((RemainingBytes(data), &[]))
62 }
63}
64
65impl<'a> RemainingBytes<'a> {
66 pub(crate) fn into_inner(self) -> &'a [u8] {
67 self.0
68 }
69}
70
71param!(struct BdAddr([u8; 6]));
72
73impl BdAddr {
74 pub fn new(val: [u8; 6]) -> Self {
76 Self(val)
77 }
78
79 pub fn raw(&self) -> &[u8] {
81 &self.0[..]
82 }
83}
84
85unsafe impl ByteAlignedValue for BdAddr {}
86
87impl<'de> crate::FromHciBytes<'de> for &'de BdAddr {
88 #[inline(always)]
89 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
90 <BdAddr as crate::ByteAlignedValue>::ref_from_hci_bytes(data)
91 }
92}
93
94param!(struct ConnHandle(u16));
95
96impl ConnHandle {
97 pub fn new(val: u16) -> Self {
99 assert!(val <= 0xeff);
100 Self(val)
101 }
102
103 pub fn raw(&self) -> u16 {
105 self.0
106 }
107}
108
109#[repr(transparent)]
111#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
112#[cfg_attr(feature = "defmt", derive(defmt::Format))]
113pub struct DurationU8<const US: u32 = 125>(u8);
114
115unsafe impl<const US: u32> FixedSizeValue for DurationU8<US> {
116 #[inline(always)]
117 fn is_valid(_data: &[u8]) -> bool {
118 true
119 }
120}
121
122impl<const US: u32> DurationU8<US> {
123 #[inline(always)]
124 pub const fn from_u8(val: u8) -> Self {
126 Self(val)
127 }
128
129 #[inline(always)]
131 pub fn from_micros(val: u64) -> Self {
132 Self::from_u8(unwrap!((val / u64::from(US)).try_into()))
133 }
134
135 #[inline(always)]
137 pub fn from_millis(val: u32) -> Self {
138 Self::from_micros(u64::from(val) * 1000)
139 }
140
141 #[inline(always)]
143 pub fn from_secs(val: u32) -> Self {
144 Self::from_micros(u64::from(val) * 1_000_000)
145 }
146
147 #[inline(always)]
149 pub fn as_u8(&self) -> u8 {
150 self.0
151 }
152
153 #[inline(always)]
155 pub fn as_micros(&self) -> u64 {
156 u64::from(self.as_u8()) * u64::from(US)
157 }
158
159 #[inline(always)]
161 pub fn as_millis(&self) -> u32 {
162 (self.as_micros() / 1000) as u32
163 }
164
165 #[inline(always)]
167 pub fn as_secs(&self) -> u32 {
168 (self.as_micros() / 1_000_000) as u32
169 }
170}
171
172#[cfg(feature = "embassy-time")]
173impl<const US: u32> From<embassy_time::Duration> for DurationU8<US> {
174 fn from(duration: embassy_time::Duration) -> Self {
175 Self::from_micros(duration.as_micros())
176 }
177}
178
179#[repr(transparent)]
181#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
182#[cfg_attr(feature = "defmt", derive(defmt::Format))]
183pub struct Duration<const US: u32 = 625>(u16);
184
185unsafe impl<const US: u32> FixedSizeValue for Duration<US> {
186 #[inline(always)]
187 fn is_valid(_data: &[u8]) -> bool {
188 true
189 }
190}
191
192impl<const US: u32> Duration<US> {
193 #[inline(always)]
194 pub const fn from_u16(val: u16) -> Self {
196 Self(val)
197 }
198
199 #[inline(always)]
201 pub fn from_micros(val: u64) -> Self {
202 Self::from_u16(unwrap!((val / u64::from(US)).try_into()))
203 }
204
205 #[inline(always)]
207 pub fn from_millis(val: u32) -> Self {
208 Self::from_micros(u64::from(val) * 1000)
209 }
210
211 #[inline(always)]
213 pub fn from_secs(val: u32) -> Self {
214 Self::from_micros(u64::from(val) * 1_000_000)
215 }
216
217 #[inline(always)]
219 pub fn as_u16(&self) -> u16 {
220 self.0
221 }
222
223 #[inline(always)]
225 pub fn as_micros(&self) -> u64 {
226 u64::from(self.as_u16()) * u64::from(US)
227 }
228
229 #[inline(always)]
231 pub fn as_millis(&self) -> u32 {
232 unwrap!((self.as_micros() / 1000).try_into())
233 }
234
235 #[inline(always)]
237 pub fn as_secs(&self) -> u32 {
238 (self.as_micros() / 1_000_000) as u32
240 }
241}
242
243#[cfg(feature = "embassy-time")]
244impl<const US: u32> From<embassy_time::Duration> for Duration<US> {
245 fn from(duration: embassy_time::Duration) -> Self {
246 Self::from_micros(duration.as_micros())
247 }
248}
249
250#[repr(transparent)]
252#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
253#[cfg_attr(feature = "defmt", derive(defmt::Format))]
254pub struct ExtDuration<const US: u16 = 1>([u8; 3]);
255
256unsafe impl<const US: u16> FixedSizeValue for ExtDuration<US> {
257 #[inline(always)]
258 fn is_valid(_data: &[u8]) -> bool {
259 true
260 }
261}
262
263unsafe impl<const US: u16> ByteAlignedValue for ExtDuration<US> {}
264
265impl<'de, const US: u16> FromHciBytes<'de> for &'de ExtDuration<US> {
266 #[inline(always)]
267 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
268 <ExtDuration<US> as crate::ByteAlignedValue>::ref_from_hci_bytes(data)
269 }
270}
271
272impl<const US: u16> ExtDuration<US> {
273 #[inline(always)]
275 pub fn from_u32(val: u32) -> Self {
276 assert!(val < (1 << 24));
277 Self(*unwrap!(val.to_le_bytes().first_chunk()))
278 }
279
280 #[inline(always)]
282 pub fn from_micros(val: u64) -> Self {
283 Self::from_u32(unwrap!((val / u64::from(US)).try_into()))
284 }
285
286 #[inline(always)]
288 pub fn from_millis(val: u32) -> Self {
289 Self::from_micros(u64::from(val) * 1000)
290 }
291
292 #[inline(always)]
294 pub fn from_secs(val: u32) -> Self {
295 Self::from_micros(u64::from(val) * 1_000_000)
296 }
297
298 #[inline(always)]
300 pub fn as_micros(&self) -> u64 {
301 u64::from_le_bytes([self.0[0], self.0[1], self.0[2], 0, 0, 0, 0, 0]) * u64::from(US)
302 }
303
304 #[inline(always)]
306 pub fn as_millis(&self) -> u32 {
307 (self.as_micros() / 1000) as u32
309 }
310
311 #[inline(always)]
313 pub fn as_secs(&self) -> u32 {
314 (self.as_micros() / 1_000_000) as u32
316 }
317}
318
319#[cfg(feature = "embassy-time")]
320impl<const US: u16> From<embassy_time::Duration> for ExtDuration<US> {
321 fn from(duration: embassy_time::Duration) -> Self {
322 Self::from_micros(duration.as_micros())
323 }
324}
325
326param!(
327 enum DisconnectReason {
328 AuthenticationFailure = 0x05,
329 RemoteUserTerminatedConn = 0x13,
330 RemoteDeviceTerminatedConnLowResources = 0x14,
331 RemoteDeviceTerminatedConnPowerOff = 0x15,
332 UnsupportedRemoteFeature = 0x1A,
333 PairingWithUnitKeyNotSupported = 0x29,
334 UnacceptableConnParameters = 0x3b,
335 }
336);
337
338param!(
339 enum RemoteConnectionParamsRejectReason {
340 UnacceptableConnParameters = 0x3b,
341 }
342);
343
344param! {
345 #[derive(Default)]
346 enum PowerLevelKind {
347 #[default]
348 Current = 0,
349 Maximum = 1,
350 }
351}
352
353param! {
354 #[derive(Default)]
355 enum ControllerToHostFlowControl {
356 #[default]
357 Off = 0,
358 AclOnSyncOff = 1,
359 AclOffSyncOn = 2,
360 BothOn = 3,
361 }
362}
363
364param!(struct CoreSpecificationVersion(u8));
365
366#[allow(missing_docs)]
367impl CoreSpecificationVersion {
368 pub const VERSION_1_0B: CoreSpecificationVersion = CoreSpecificationVersion(0x00);
369 pub const VERSION_1_1: CoreSpecificationVersion = CoreSpecificationVersion(0x01);
370 pub const VERSION_1_2: CoreSpecificationVersion = CoreSpecificationVersion(0x02);
371 pub const VERSION_2_0_EDR: CoreSpecificationVersion = CoreSpecificationVersion(0x03);
372 pub const VERSION_2_1_EDR: CoreSpecificationVersion = CoreSpecificationVersion(0x04);
373 pub const VERSION_3_0_HS: CoreSpecificationVersion = CoreSpecificationVersion(0x05);
374 pub const VERSION_4_0: CoreSpecificationVersion = CoreSpecificationVersion(0x06);
375 pub const VERSION_4_1: CoreSpecificationVersion = CoreSpecificationVersion(0x07);
376 pub const VERSION_4_2: CoreSpecificationVersion = CoreSpecificationVersion(0x08);
377 pub const VERSION_5_0: CoreSpecificationVersion = CoreSpecificationVersion(0x09);
378 pub const VERSION_5_1: CoreSpecificationVersion = CoreSpecificationVersion(0x0A);
379 pub const VERSION_5_2: CoreSpecificationVersion = CoreSpecificationVersion(0x0B);
380 pub const VERSION_5_3: CoreSpecificationVersion = CoreSpecificationVersion(0x0C);
381 pub const VERSION_5_4: CoreSpecificationVersion = CoreSpecificationVersion(0x0D);
382}
383
384unsafe impl ByteAlignedValue for CoreSpecificationVersion {}
385
386impl<'de> crate::FromHciBytes<'de> for &'de CoreSpecificationVersion {
387 #[inline(always)]
388 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
389 <CoreSpecificationVersion as crate::ByteAlignedValue>::ref_from_hci_bytes(data)
390 }
391}
392
393param! {
394 #[derive(Default)]
395 enum LinkType {
396 #[default]
397 SyncData = 0,
398 AclData = 1,
399 IsoData = 2,
400 }
401}
402
403param_slice! {
404 [ConnHandleCompletedPackets; 4] {
405 handle[0]: ConnHandle,
406 num_completed_packets[2]: u16,
407 }
408}
409
410impl ConnHandleCompletedPackets {
411 pub fn new(handle: ConnHandle, num_completed_packets: u16) -> Self {
413 let mut dest = [0; 4];
414 handle.write_hci(&mut dest[0..2]).unwrap();
415 num_completed_packets.write_hci(&mut dest[2..4]).unwrap();
416 Self(dest)
417 }
418}
419
420#[cfg(test)]
421mod tests {
422 #[cfg(feature = "serde")]
423 use postcard;
424
425 use super::*;
426
427 #[test]
428 fn test_encode_decode_conn_handle_completed_packets() {
429 let completed = ConnHandleCompletedPackets::new(ConnHandle::new(42), 2334);
430
431 assert_eq!(completed.handle().unwrap(), ConnHandle::new(42));
432 assert_eq!(completed.num_completed_packets().unwrap(), 2334);
433 }
434
435 #[cfg(feature = "serde")]
436 #[test]
437 fn test_serialize_bdaddr() {
438 let bytes = [0x01, 0xaa, 0x55, 0x04, 0x05, 0xfe];
439
440 let address = BdAddr::new(bytes);
441
442 let mut buffer = [0u8; 32];
443 let vykort = postcard::to_slice(&address, &mut buffer).unwrap();
444
445 assert_eq!(vykort, &bytes);
446 }
447
448 #[cfg(feature = "serde")]
449 #[test]
450 fn test_deserialize_bdaddr() {
451 let bytes = [0xff, 0x5a, 0xa5, 0x00, 0x05, 0xfe];
452
453 let address = postcard::from_bytes::<BdAddr>(&bytes).unwrap();
454
455 let expected = BdAddr::new(bytes);
456
457 assert_eq!(address, expected);
458 }
459}