esp32_nimble/utilities/
ble_uuid.rs1use alloc::string::String;
4use esp_idf_svc::sys as esp_idf_sys;
5
6#[derive(Copy, Clone)]
8pub enum BleUuid {
9 Uuid16(u16),
11 Uuid32(u32),
13 Uuid128([u8; 16]),
15}
16
17impl BleUuid {
18 #[must_use]
20 pub const fn from_uuid16(uuid: u16) -> Self {
21 Self::Uuid16(uuid)
22 }
23
24 #[must_use]
26 pub const fn from_uuid32(uuid: u32) -> Self {
27 Self::Uuid32(uuid)
28 }
29
30 #[must_use]
32 pub const fn from_uuid128(uuid: [u8; 16]) -> Self {
33 Self::Uuid128(uuid)
34 }
35
36 pub const fn from_uuid128_string(uuid: &str) -> Result<Self, uuid::Error> {
42 match uuid::Uuid::try_parse(uuid) {
47 Ok(uuid) => Ok(Self::Uuid128(uuid.as_u128().to_le_bytes())),
48 Err(err) => Err(err),
49 }
50 }
51
52 #[must_use]
53 pub(crate) fn as_uuid128_array(&self) -> [u8; 16] {
54 let base_ble_uuid = [
55 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00,
57 ];
58
59 match self {
60 Self::Uuid16(uuid) => {
61 let mut uuid128 = base_ble_uuid;
62
63 let mut uuid_as_bytes: [u8; 2] = uuid.to_be_bytes();
64 uuid_as_bytes.reverse();
65
66 uuid128[12..=13].copy_from_slice(&uuid_as_bytes[..]);
67 uuid128
68 }
69 Self::Uuid32(uuid) => {
70 let mut uuid128 = base_ble_uuid;
71
72 let mut uuid_as_bytes: [u8; 4] = uuid.to_be_bytes();
73 uuid_as_bytes.reverse();
74
75 uuid128[12..=15].copy_from_slice(&uuid_as_bytes[..]);
76 uuid128
77 }
78 Self::Uuid128(uuid) => *uuid,
79 }
80 }
81}
82
83impl PartialEq for BleUuid {
84 fn eq(&self, other: &Self) -> bool {
85 self.as_uuid128_array() == other.as_uuid128_array()
86 }
87}
88
89impl From<BleUuid> for esp_idf_sys::ble_uuid_any_t {
90 #[allow(clippy::cast_possible_truncation)]
91 fn from(val: BleUuid) -> Self {
92 let mut result: Self = Self::default();
93
94 match val {
95 BleUuid::Uuid16(uuid) => {
96 result.u.type_ = esp_idf_sys::BLE_UUID_TYPE_16 as _;
97 result.u16_.value = uuid;
98 }
99 BleUuid::Uuid32(uuid) => {
100 result.u.type_ = esp_idf_sys::BLE_UUID_TYPE_32 as _;
101 result.u32_.value = uuid;
102 }
103 BleUuid::Uuid128(uuid) => {
104 result.u.type_ = esp_idf_sys::BLE_UUID_TYPE_128 as _;
105 result.u128_.value = uuid;
106 }
107 }
108
109 result
110 }
111}
112
113impl From<esp_idf_sys::ble_uuid_any_t> for BleUuid {
114 fn from(uuid: esp_idf_sys::ble_uuid_any_t) -> Self {
115 unsafe {
116 match uuid.u.type_ as _ {
117 esp_idf_sys::BLE_UUID_TYPE_16 => Self::Uuid16(uuid.u16_.value),
118 esp_idf_sys::BLE_UUID_TYPE_32 => Self::Uuid32(uuid.u32_.value),
119 esp_idf_sys::BLE_UUID_TYPE_128 => Self::Uuid128(uuid.u128_.value),
120 _ => unreachable!("Invalid UUID length"),
122 }
123 }
124 }
125}
126
127impl core::fmt::Display for BleUuid {
128 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
129 match self {
130 Self::Uuid16(uuid) => write!(f, "0x{uuid:04x}"),
131 Self::Uuid32(uuid) => write!(f, "0x{uuid:08x}"),
132 Self::Uuid128(uuid) => {
133 let mut uuid = *uuid;
134 uuid.reverse();
135
136 let mut uuid_str = String::new();
137
138 for byte in &uuid {
139 uuid_str.push_str(&alloc::format!("{byte:02x}"));
140 }
141 uuid_str.insert(8, '-');
142 uuid_str.insert(13, '-');
143 uuid_str.insert(18, '-');
144 uuid_str.insert(23, '-');
145
146 write!(f, "{uuid_str}")
147 }
148 }
149 }
150}
151
152impl core::fmt::Debug for BleUuid {
153 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
154 write!(f, "{self}")
155 }
156}
157
158impl From<uuid::Uuid> for BleUuid {
159 fn from(uuid: uuid::Uuid) -> Self {
160 let mut bytes = *uuid.as_bytes();
161 bytes.reverse();
162 Self::Uuid128(bytes)
163 }
164}
165
166#[macro_export]
167macro_rules! uuid128 {
169 ($uuid:expr) => {{ $crate::utilities::BleUuid::Uuid128($crate::uuid_macro!($uuid).as_u128().to_le_bytes()) }};
170}