1#![no_std]
2
3#[cfg(feature = "alloc")]
6extern crate alloc;
7
8#[cfg(feature = "std")]
9extern crate std;
10
11use core::array::TryFromSliceError;
12use core::fmt::{Debug, Display};
13
14pub mod ad_types;
15pub mod appearance;
16pub mod browse_group_identifiers;
17pub mod characteristic;
18pub mod declarations;
19pub mod descriptors;
20pub mod mesh_profile;
21pub mod object_types;
22pub mod protocol_identifiers;
23pub mod service;
24pub mod service_class;
25pub mod units;
26
27#[deprecated(since = "0.1.0", note = "use BluetoothUuid128::base() instead.")]
28#[doc(hidden)]
29pub const BLUETOOTH_BASE_UUID: [u8; 16] = [
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
32];
33
34#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37pub enum BluetoothUuid {
38 Uuid16(BluetoothUuid16),
40 Uuid32(BluetoothUuid32),
42 Uuid128(BluetoothUuid128),
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
50#[cfg_attr(feature = "defmt", derive(defmt::Format))]
51pub struct InvalidLengthError;
52
53impl Display for InvalidLengthError {
54 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55 f.write_str("Invalid byte length for Bluetooth UUID")
56 }
57}
58
59impl core::error::Error for InvalidLengthError {}
60
61impl From<TryFromSliceError> for InvalidLengthError {
62 fn from(_: TryFromSliceError) -> Self {
63 InvalidLengthError
64 }
65}
66
67impl BluetoothUuid {
68 pub const fn nil() -> Self {
70 Self::Uuid128(BluetoothUuid128::nil())
71 }
72
73 pub const fn from_u16(v: u16) -> Self {
75 Self::Uuid16(BluetoothUuid16::new(v))
76 }
77
78 pub const fn from_u32(v: u32) -> Self {
82 if v <= u16::MAX as u32 {
83 Self::from_u16(v as u16)
84 } else {
85 Self::Uuid32(BluetoothUuid32::new(v))
86 }
87 }
88
89 pub const fn from_u128(v: u128) -> Self {
94 let uuid = BluetoothUuid128::new(v);
95 let (_, base_d2, base_d3, base_d4) = BluetoothUuid128::base().to_fields();
96 let (d1, d2, d3, d4) = uuid.to_fields();
97 if d2 == base_d2 && d3 == base_d3 && d4 == base_d4 {
98 Self::from_u32(d1)
99 } else {
100 Self::Uuid128(uuid)
101 }
102 }
103
104 pub fn from_le_slice(b: &[u8]) -> Result<Self, InvalidLengthError> {
108 match b.len() {
109 2 => Ok(BluetoothUuid16::from_le_slice(b)?.into()),
110 4 => Ok(BluetoothUuid32::from_le_slice(b)?.into()),
111 16 => Ok(BluetoothUuid128::from_le_slice(b)?.into()),
112 _ => Err(InvalidLengthError),
113 }
114 }
115
116 pub fn from_be_slice(b: &[u8]) -> Result<Self, InvalidLengthError> {
120 match b.len() {
121 2 => Ok(BluetoothUuid16::from_be_slice(b)?.into()),
122 4 => Ok(BluetoothUuid32::from_be_slice(b)?.into()),
123 16 => Ok(BluetoothUuid128::from_be_slice(b)?.into()),
124 _ => Err(InvalidLengthError),
125 }
126 }
127
128 pub const fn to_u128(&self) -> u128 {
130 match self {
131 Self::Uuid16(uuid) => BluetoothUuid128::base().set_initial_group(uuid.to_u16() as u32),
132 Self::Uuid32(uuid) => BluetoothUuid128::base().set_initial_group(uuid.to_u32()),
133 Self::Uuid128(uuid) => *uuid,
134 }
135 .to_u128()
136 }
137
138 pub const fn as_le_slice(&self) -> &[u8] {
142 match self {
143 Self::Uuid16(uuid) => uuid.as_le_slice(),
144 Self::Uuid32(uuid) => uuid.as_le_slice(),
145 Self::Uuid128(uuid) => uuid.as_le_slice(),
146 }
147 }
148}
149
150impl Debug for BluetoothUuid {
151 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
152 write!(f, "BluetoothUuid({})", self)
153 }
154}
155
156impl Display for BluetoothUuid {
157 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
158 match self {
159 BluetoothUuid::Uuid16(uuid) => Display::fmt(uuid, f),
160 BluetoothUuid::Uuid32(uuid) => Display::fmt(uuid, f),
161 BluetoothUuid::Uuid128(uuid) => Display::fmt(uuid, f),
162 }
163 }
164}
165
166#[cfg(feature = "defmt")]
167impl defmt::Format for BluetoothUuid {
168 fn format(&self, fmt: defmt::Formatter) {
169 match self {
170 BluetoothUuid::Uuid16(uuid) => defmt::write!(fmt, "{}", uuid),
171 BluetoothUuid::Uuid32(uuid) => defmt::write!(fmt, "{}", uuid),
172 BluetoothUuid::Uuid128(uuid) => defmt::write!(fmt, "{}", uuid),
173 }
174 }
175}
176
177impl Default for BluetoothUuid {
178 fn default() -> Self {
179 Self::nil()
180 }
181}
182
183impl AsRef<[u8]> for BluetoothUuid {
184 fn as_ref(&self) -> &[u8] {
185 self.as_le_slice()
186 }
187}
188
189impl From<BluetoothUuid16> for BluetoothUuid {
190 fn from(value: BluetoothUuid16) -> Self {
191 Self::Uuid16(value)
192 }
193}
194
195impl From<u16> for BluetoothUuid {
196 fn from(value: u16) -> Self {
197 Self::from_u16(value)
198 }
199}
200
201impl From<[u8; 2]> for BluetoothUuid {
202 fn from(value: [u8; 2]) -> Self {
203 Self::Uuid16(BluetoothUuid16(value))
205 }
206}
207
208impl From<BluetoothUuid32> for BluetoothUuid {
209 fn from(value: BluetoothUuid32) -> Self {
210 Self::from_u32(value.to_u32())
211 }
212}
213
214impl From<u32> for BluetoothUuid {
215 fn from(value: u32) -> Self {
216 Self::from_u32(value)
217 }
218}
219
220impl From<[u8; 4]> for BluetoothUuid {
221 fn from(value: [u8; 4]) -> Self {
222 Self::Uuid32(BluetoothUuid32(value))
224 }
225}
226
227impl From<BluetoothUuid128> for BluetoothUuid {
228 fn from(value: BluetoothUuid128) -> Self {
229 Self::from_u128(value.to_u128())
230 }
231}
232
233impl From<u128> for BluetoothUuid {
234 fn from(value: u128) -> Self {
235 Self::from_u128(value)
236 }
237}
238
239impl From<[u8; 16]> for BluetoothUuid {
240 fn from(value: [u8; 16]) -> Self {
241 Self::Uuid128(BluetoothUuid128(value))
243 }
244}
245
246#[cfg(feature = "uuid")]
247impl From<uuid::Uuid> for BluetoothUuid {
248 fn from(value: uuid::Uuid) -> Self {
249 BluetoothUuid128::new(value.as_u128()).into()
250 }
251}
252
253#[cfg(feature = "uuid")]
254impl From<BluetoothUuid> for uuid::Uuid {
255 fn from(value: BluetoothUuid) -> Self {
256 uuid::Uuid::from_u128(value.to_u128())
257 }
258}
259
260#[cfg(feature = "alloc")]
261impl From<BluetoothUuid> for alloc::vec::Vec<u8> {
262 fn from(value: BluetoothUuid) -> Self {
263 value.as_le_slice().to_vec()
264 }
265}
266
267#[cfg(feature = "alloc")]
268impl TryFrom<alloc::vec::Vec<u8>> for BluetoothUuid {
269 type Error = InvalidLengthError;
270
271 fn try_from(value: alloc::vec::Vec<u8>) -> Result<Self, Self::Error> {
272 Self::from_le_slice(&value)
273 }
274}
275
276macro_rules! impl_uuid {
277 {
278 $(#[$attrs:meta])*
279 struct $name:ident($num:ty, $bytes:expr, $to:ident);
280 } => {
281 #[repr(transparent)]
282 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
283 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
284 $(#[$attrs])*
285 pub struct $name([u8; $bytes]);
286
287 impl $name {
288 pub const fn new(uuid: $num) -> Self {
290 Self(uuid.to_le_bytes())
291 }
292
293 pub const fn from_le_bytes(bytes: [u8; $bytes]) -> Self {
295 Self(bytes)
296 }
297
298 pub fn from_be_bytes(mut bytes: [u8; $bytes]) -> Self {
300 bytes.reverse();
301 Self(bytes)
302 }
303
304 pub fn from_le_slice(bytes: &[u8]) -> Result<Self, InvalidLengthError> {
306 Ok(Self::from_le_bytes(bytes.try_into()?))
307 }
308
309 pub fn from_be_slice(bytes: &[u8]) -> Result<Self, InvalidLengthError> {
311 let mut bytes: [u8; $bytes] = bytes.try_into()?;
312 bytes.reverse();
313 Ok(Self::from_le_bytes(bytes))
314 }
315
316 pub const fn as_le_bytes(&self) -> &[u8; $bytes] {
318 &self.0
319 }
320
321 pub const fn to_le_bytes(self) -> [u8; $bytes] {
323 self.0
324 }
325
326 pub fn to_be_bytes(self) -> [u8; $bytes] {
328 let mut bytes = self.0;
329 bytes.reverse();
330 bytes
331 }
332
333 pub const fn as_le_slice(&self) -> &[u8] {
335 &self.0
336 }
337
338 pub const fn $to(self) -> $num {
340 <$num>::from_le_bytes(self.0)
341 }
342 }
343
344 impl AsRef<[u8]> for $name {
345 fn as_ref(&self) -> &[u8] {
346 self.as_le_bytes()
347 }
348 }
349
350 impl From<$num> for $name {
351 fn from(value: $num) -> Self {
352 Self::new(value)
353 }
354 }
355
356 impl From<$name> for $num {
357 fn from(value: $name) -> Self {
358 value.$to()
359 }
360 }
361
362 impl From<[u8; $bytes]> for $name {
363 fn from(value: [u8; $bytes]) -> Self {
364 Self(value)
366 }
367 }
368
369 impl From<$name> for [u8; $bytes] {
370 fn from(value: $name) -> Self {
371 value.0
372 }
373 }
374
375 #[cfg(feature = "uuid")]
376 impl From<$name> for uuid::Uuid {
377 fn from(value: $name) -> Self {
378 BluetoothUuid::from(value).into()
379 }
380 }
381 };
382
383 {
384 $(#[$attrs:meta])*
385 struct $name:ident($num:ty, $bytes:expr, $to:ident, $fmt:literal, $defmt:literal);
386 } => {
387 impl_uuid! { $(#[$attrs])* struct $name($num, $bytes, $to); }
388
389 impl Debug for $name {
390 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
391 write!(f, concat!(stringify!($name), "(0x{})"), self)
392 }
393 }
394
395 impl Display for $name {
396 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
397 write!(f, $fmt, self.$to())
398 }
399 }
400
401 #[cfg(feature = "defmt")]
402 impl defmt::Format for $name {
403 fn format(&self, f: defmt::Formatter) {
404 defmt::write!(f, $defmt, self.0)
405 }
406 }
407 };
408}
409
410impl_uuid! {
411 struct BluetoothUuid16(u16, 2, to_u16, "0x{:04X}", "BluetoothUuid16({:04X})");
413}
414impl_uuid! {
415 struct BluetoothUuid32(u32, 4, to_u32, "0x{:08X}", "BluetoothUuid32({:08X})");
417}
418impl_uuid! {
419 struct BluetoothUuid128(u128, 16, to_u128);
421}
422
423impl BluetoothUuid128 {
424 pub const fn base() -> Self {
435 BluetoothUuid128::new(0x00000000_0000_1000_8000_00805F9B34FB)
436 }
437
438 pub const fn nil() -> Self {
440 Self([0; 16])
441 }
442
443 pub const fn to_fields(&self) -> (u32, u16, u16, u64) {
447 let b = &self.0;
448 let d4 = u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]);
449 let d3 = u16::from_le_bytes([b[8], b[9]]);
450 let d2 = u16::from_le_bytes([b[10], b[11]]);
451 let d1 = u32::from_le_bytes([b[12], b[13], b[14], b[15]]);
452 (d1, d2, d3, d4)
453 }
454
455 pub const fn set_initial_group(mut self, val: u32) -> Self {
460 let bytes = val.to_le_bytes();
461 self.0[12] = bytes[0];
462 self.0[13] = bytes[1];
463 self.0[14] = bytes[2];
464 self.0[15] = bytes[3];
465 self
466 }
467}
468
469impl Default for BluetoothUuid128 {
470 fn default() -> Self {
471 Self::nil()
472 }
473}
474
475impl Debug for BluetoothUuid128 {
476 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
477 write!(f, concat!(stringify!($name), "(0x{})"), self)
478 }
479}
480
481impl Display for BluetoothUuid128 {
482 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
483 let (d1, d2, d3, d4) = self.to_fields();
484 write!(
485 f,
486 "{:08X}-{:04X}-{:04X}-{:04X}-{:012X}",
487 d1,
488 d2,
489 d3,
490 d4 >> 48,
491 d4 & ((1 << 48) - 1)
492 )
493 }
494}
495
496#[cfg(feature = "defmt")]
497impl defmt::Format for BluetoothUuid128 {
498 fn format(&self, f: defmt::Formatter) {
499 let (d1, d2, d3, d4) = self.to_fields();
500 defmt::write!(
501 f,
502 "BluetoothUuid128({=u32:08X}-{=u16:04X}-{=u16:04X}-{=u16:04X}-{=u64:012X})",
503 d1,
504 d2,
505 d3,
506 (d4 >> 48) as u16,
507 d4 & ((1 << 48) - 1)
508 )
509 }
510}
511
512#[cfg(test)]
513mod test {
514 use super::*;
515
516 #[test]
517 fn test_ble_uuid() {
518 const BLE_UUID: BluetoothUuid16 = BluetoothUuid16::new(0x1234);
519 assert_eq!(u16::from(BLE_UUID), 0x1234);
520 let uuid: u16 = BLE_UUID.into();
521 assert_eq!(uuid, 0x1234);
522 const UUID: [u8; 2] = BLE_UUID.to_le_bytes();
523 assert_eq!(UUID, [0x34, 0x12]);
524 }
525
526 #[cfg(feature = "uuid")]
527 #[test]
528 fn test_uuid_conversion() {
529 let result = uuid::Uuid::from(BluetoothUuid16::new(0x1234));
530 let expected = "00001234-0000-1000-8000-00805f9b34fb".parse::<uuid::Uuid>().unwrap();
531
532 assert_eq!(result.into_bytes(), expected.into_bytes());
534 }
535}