btleplug/api/
bleuuid.rs

1//! Utilities for dealing with BLE UUIDs, converting to and from their short formats.
2
3use uuid::Uuid;
4
5const BLUETOOTH_BASE_UUID: u128 = 0x00000000_0000_1000_8000_00805f9b34fb;
6const BLUETOOTH_BASE_MASK: u128 = 0x00000000_ffff_ffff_ffff_ffffffffffff;
7const BLUETOOTH_BASE_MASK_16: u128 = 0xffff0000_ffff_ffff_ffff_ffffffffffff;
8
9// TODO: Make these functions part of the `BleUuid` trait once const fn is allowed there.
10/// Convert a 32-bit BLE short UUID to a full 128-bit UUID by filling in the standard Bluetooth Base
11/// UUID.
12pub const fn uuid_from_u32(short: u32) -> Uuid {
13    Uuid::from_u128(BLUETOOTH_BASE_UUID | ((short as u128) << 96))
14}
15
16/// Convert a 16-bit BLE short UUID to a full 128-bit UUID by filling in the standard Bluetooth Base
17/// UUID.
18pub const fn uuid_from_u16(short: u16) -> Uuid {
19    uuid_from_u32(short as u32)
20}
21
22/// An extension trait for `Uuid` which provides BLE-specific methods.
23pub trait BleUuid {
24    /// If the UUID is a valid BLE short UUID then return its short form, otherwise return `None`.
25    fn to_ble_u32(&self) -> Option<u32>;
26
27    /// If the UUID is a valid 16-bit BLE short UUID then return its short form, otherwise return
28    /// `None`.
29    fn to_ble_u16(&self) -> Option<u16>;
30
31    /// Convert the UUID to a string, using short format if applicable.
32    fn to_short_string(&self) -> String;
33}
34
35impl BleUuid for Uuid {
36    fn to_ble_u32(&self) -> Option<u32> {
37        let value = self.as_u128();
38        if value & BLUETOOTH_BASE_MASK == BLUETOOTH_BASE_UUID {
39            Some((value >> 96) as u32)
40        } else {
41            None
42        }
43    }
44
45    fn to_ble_u16(&self) -> Option<u16> {
46        let value = self.as_u128();
47        if value & BLUETOOTH_BASE_MASK_16 == BLUETOOTH_BASE_UUID {
48            Some((value >> 96) as u16)
49        } else {
50            None
51        }
52    }
53
54    fn to_short_string(&self) -> String {
55        if let Some(uuid16) = self.to_ble_u16() {
56            format!("{:#04x}", uuid16)
57        } else if let Some(uuid32) = self.to_ble_u32() {
58            format!("{:#06x}", uuid32)
59        } else {
60            self.to_string()
61        }
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn uuid_from_u32_test() {
71        assert_eq!(
72            uuid_from_u32(0x11223344),
73            Uuid::parse_str("11223344-0000-1000-8000-00805f9b34fb").unwrap()
74        );
75    }
76
77    #[test]
78    fn uuid_from_u16_test() {
79        assert_eq!(
80            uuid_from_u16(0x1122),
81            Uuid::parse_str("00001122-0000-1000-8000-00805f9b34fb").unwrap()
82        );
83    }
84
85    #[test]
86    fn uuid_to_from_u16_success() {
87        let uuid = Uuid::parse_str("00001234-0000-1000-8000-00805f9b34fb").unwrap();
88        assert_eq!(uuid_from_u16(uuid.to_ble_u16().unwrap()), uuid);
89    }
90
91    #[test]
92    fn uuid_to_from_u32_success() {
93        let uuid = Uuid::parse_str("12345678-0000-1000-8000-00805f9b34fb").unwrap();
94        assert_eq!(uuid_from_u32(uuid.to_ble_u32().unwrap()), uuid);
95    }
96
97    #[test]
98    fn uuid_to_u16_fail() {
99        assert_eq!(
100            Uuid::parse_str("12345678-0000-1000-8000-00805f9b34fb")
101                .unwrap()
102                .to_ble_u16(),
103            None
104        );
105        assert_eq!(
106            Uuid::parse_str("12340000-0000-1000-8000-00805f9b34fb")
107                .unwrap()
108                .to_ble_u16(),
109            None
110        );
111        assert_eq!(Uuid::nil().to_ble_u16(), None);
112    }
113
114    #[test]
115    fn uuid_to_u32_fail() {
116        assert_eq!(
117            Uuid::parse_str("12345678-9000-1000-8000-00805f9b34fb")
118                .unwrap()
119                .to_ble_u32(),
120            None
121        );
122        assert_eq!(Uuid::nil().to_ble_u32(), None);
123    }
124
125    #[test]
126    fn to_short_string_u16() {
127        let uuid = uuid_from_u16(0x1122);
128        assert_eq!(uuid.to_short_string(), "0x1122");
129    }
130
131    #[test]
132    fn to_short_string_u32() {
133        let uuid = uuid_from_u32(0x11223344);
134        assert_eq!(uuid.to_short_string(), "0x11223344");
135    }
136
137    #[test]
138    fn to_short_string_long() {
139        let uuid_str = "12345678-9000-1000-8000-00805f9b34fb";
140        let uuid = Uuid::parse_str(uuid_str).unwrap();
141        assert_eq!(uuid.to_short_string(), uuid_str);
142    }
143}