1use bt_common::{PeerId, Uuid};
6use thiserror::Error;
7
8#[derive(Debug, Copy, Clone, PartialEq)]
12pub enum GattError {
13 InvalidHandle = 1,
14 ReadNotPermitted = 2,
15 WriteNotPermitted = 3,
16 InvalidPdu = 4,
17 InsufficientAuthentication = 5,
18 InvalidOffset = 7,
19 InsufficientAuthorization = 8,
20 InsufficientEncryptionKeySize = 12,
21 InvalidAttributeValueLength = 13,
22 UnlikelyError = 14,
23 InsufficientEncryption = 15,
24 InsufficientResources = 17,
25 ValueNotAllowed = 19,
26 ApplicationError80 = 128,
27 ApplicationError81 = 129,
28 ApplicationError82 = 130,
29 ApplicationError83 = 131,
30 ApplicationError84 = 132,
31 ApplicationError85 = 133,
32 ApplicationError86 = 134,
33 ApplicationError87 = 135,
34 ApplicationError88 = 136,
35 ApplicationError89 = 137,
36 ApplicationError8A = 138,
37 ApplicationError8B = 139,
38 ApplicationError8C = 140,
39 ApplicationError8D = 141,
40 ApplicationError8E = 142,
41 ApplicationError8F = 143,
42 ApplicationError90 = 144,
43 ApplicationError91 = 145,
44 ApplicationError92 = 146,
45 ApplicationError93 = 147,
46 ApplicationError94 = 148,
47 ApplicationError95 = 149,
48 ApplicationError96 = 150,
49 ApplicationError97 = 151,
50 ApplicationError98 = 152,
51 ApplicationError99 = 153,
52 ApplicationError9A = 154,
53 ApplicationError9B = 155,
54 ApplicationError9C = 156,
55 ApplicationError9D = 157,
56 ApplicationError9E = 158,
57 ApplicationError9F = 159,
58 WriteRequestRejected = 252,
59 CccDescriptorImproperlyConfigured = 253,
60 ProcedureAlreadyInProgress = 254,
61 OutOfRange = 255,
62 InvalidParameters = 257,
63 TooManyResults = 258,
64}
65
66impl std::fmt::Display for GattError {
67 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68 write!(f, "{:?}", self)
69 }
70}
71
72impl std::error::Error for GattError {}
73
74impl TryFrom<u32> for GattError {
75 type Error = Error;
76
77 fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
78 match value {
79 1 => Ok(Self::InvalidHandle),
80 2 => Ok(Self::ReadNotPermitted),
81 3 => Ok(Self::WriteNotPermitted),
82 4 => Ok(Self::InvalidPdu),
83 5 => Ok(Self::InsufficientAuthentication),
84 7 => Ok(Self::InvalidOffset),
85 8 => Ok(Self::InsufficientAuthorization),
86 12 => Ok(Self::InsufficientEncryptionKeySize),
87 13 => Ok(Self::InvalidAttributeValueLength),
88 14 => Ok(Self::UnlikelyError),
89 15 => Ok(Self::InsufficientEncryption),
90 17 => Ok(Self::InsufficientResources),
91 19 => Ok(Self::ValueNotAllowed),
92 128 => Ok(Self::ApplicationError80),
93 129 => Ok(Self::ApplicationError81),
94 130 => Ok(Self::ApplicationError82),
95 131 => Ok(Self::ApplicationError83),
96 132 => Ok(Self::ApplicationError84),
97 133 => Ok(Self::ApplicationError85),
98 134 => Ok(Self::ApplicationError86),
99 135 => Ok(Self::ApplicationError87),
100 136 => Ok(Self::ApplicationError88),
101 137 => Ok(Self::ApplicationError89),
102 138 => Ok(Self::ApplicationError8A),
103 139 => Ok(Self::ApplicationError8B),
104 140 => Ok(Self::ApplicationError8C),
105 141 => Ok(Self::ApplicationError8D),
106 142 => Ok(Self::ApplicationError8E),
107 143 => Ok(Self::ApplicationError8F),
108 144 => Ok(Self::ApplicationError90),
109 145 => Ok(Self::ApplicationError91),
110 146 => Ok(Self::ApplicationError92),
111 147 => Ok(Self::ApplicationError93),
112 148 => Ok(Self::ApplicationError94),
113 149 => Ok(Self::ApplicationError95),
114 150 => Ok(Self::ApplicationError96),
115 151 => Ok(Self::ApplicationError97),
116 152 => Ok(Self::ApplicationError98),
117 153 => Ok(Self::ApplicationError99),
118 154 => Ok(Self::ApplicationError9A),
119 155 => Ok(Self::ApplicationError9B),
120 156 => Ok(Self::ApplicationError9C),
121 157 => Ok(Self::ApplicationError9D),
122 158 => Ok(Self::ApplicationError9E),
123 159 => Ok(Self::ApplicationError9F),
124 252 => Ok(Self::WriteRequestRejected),
125 253 => Ok(Self::CccDescriptorImproperlyConfigured),
126 254 => Ok(Self::ProcedureAlreadyInProgress),
127 255 => Ok(Self::OutOfRange),
128 257 => Ok(Self::InvalidParameters),
129 258 => Ok(Self::TooManyResults),
130 x => Err(Error::Conversion(format!("Unknown GATT Error Value: {x}"))),
131 }
132 }
133}
134
135#[derive(Error, Debug)]
136#[non_exhaustive]
137pub enum Error {
138 #[error("peer {0} was not recognized")]
139 PeerNotRecognized(PeerId),
140 #[error("peer {0} was disconnected")]
141 PeerDisconnected(PeerId),
142 #[error("conversion error: {0}")]
143 Conversion(String),
144 #[error("scan failed: {0}")]
145 ScanFailed(String),
146 #[error("another error: {0}")]
147 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
148 #[error("GATT error: {0}")]
149 Gatt(#[from] GattError),
150 #[error("definition error: duplicate handle(s) {0:?}")]
151 DuplicateHandle(Vec<Handle>),
152 #[error("service for {0:?} already published")]
153 AlreadyPublished(crate::server::ServiceId),
154 #[error("Encoding/decoding error: {0}")]
155 Encoding(#[from] bt_common::packet_encoding::Error),
156 #[error("Periodic Advertising error: {0}")]
157 PeriodicAdvertising(crate::periodic_advertising::Error),
158}
159
160impl Error {
161 pub fn other(e: impl std::error::Error + Send + Sync + 'static) -> Self {
162 Self::Other(Box::new(e))
163 }
164}
165
166impl From<String> for Error {
167 fn from(value: String) -> Self {
168 Self::Other(Box::<dyn std::error::Error + Send + Sync>::from(value))
169 }
170}
171
172impl From<&str> for Error {
173 fn from(value: &str) -> Self {
174 String::from(value).into()
175 }
176}
177
178pub type Result<T> = core::result::Result<T, Error>;
179
180#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
198pub struct Handle(pub u64);
199
200#[derive(Clone, Copy, Debug, Eq, PartialEq)]
202pub enum ServiceKind {
203 Primary,
204 Secondary,
205}
206
207#[derive(Clone, Copy, Debug, Eq, PartialEq)]
208pub enum WriteMode {
209 None,
210 Reliable,
211 WithoutResponse,
212}
213
214#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
219pub enum CharacteristicProperty {
220 Broadcast = 0x01,
221 Read = 0x02,
222 WriteWithoutResponse = 0x04,
223 Write = 0x08,
224 Notify = 0x10,
225 Indicate = 0x20,
226 AuthenticatedSignedWrites = 0x40,
227 ReliableWrite = 0x100,
228 WritableAuxiliaries = 0x200,
229}
230
231impl std::ops::BitOr for CharacteristicProperty {
232 type Output = CharacteristicProperties;
233
234 fn bitor(self, rhs: Self) -> Self::Output {
235 CharacteristicProperties(vec![self, rhs])
236 }
237}
238
239#[derive(Default, Debug, Clone)]
240pub struct CharacteristicProperties(pub Vec<CharacteristicProperty>);
241
242impl From<CharacteristicProperty> for CharacteristicProperties {
243 fn from(value: CharacteristicProperty) -> Self {
244 Self(vec![value])
245 }
246}
247
248impl FromIterator<CharacteristicProperty> for CharacteristicProperties {
249 fn from_iter<T: IntoIterator<Item = CharacteristicProperty>>(iter: T) -> Self {
250 Self(iter.into_iter().collect())
251 }
252}
253
254impl std::ops::BitOr<CharacteristicProperty> for CharacteristicProperties {
255 type Output = Self;
256
257 fn bitor(mut self, rhs: CharacteristicProperty) -> Self::Output {
258 self.0.push(rhs);
259 self
260 }
261}
262
263impl CharacteristicProperties {
264 pub fn is_disjoint(&self, other: &Self) -> bool {
265 for property in self.0.iter() {
266 if other.0.contains(&property) {
267 return false;
268 }
269 }
270 true
271 }
272
273 pub fn contains(&self, property: CharacteristicProperty) -> bool {
274 self.0.contains(&property)
275 }
276}
277
278#[derive(Debug, Clone, Copy, Default)]
279pub struct SecurityLevels {
280 pub encryption: bool,
282 pub authentication: bool,
284 pub authorization: bool,
286}
287
288impl SecurityLevels {
289 pub fn satisfied(&self, provided: SecurityLevels) -> bool {
290 (!self.encryption || provided.encryption)
291 && (!self.authentication || provided.authentication)
292 && (!self.authorization || provided.encryption)
293 }
294
295 pub const fn encryption_required() -> Self {
296 Self { encryption: true, authentication: false, authorization: false }
297 }
298}
299
300#[derive(Debug, Clone, Copy, Default)]
301pub struct AttributePermissions {
302 pub read: Option<SecurityLevels>,
305 pub write: Option<SecurityLevels>,
308 pub update: Option<SecurityLevels>,
311}
312
313impl AttributePermissions {
314 pub fn with_levels(properties: &CharacteristicProperties, levels: &SecurityLevels) -> Self {
315 let notify_properties = CharacteristicProperty::Notify | CharacteristicProperty::Indicate;
316 Self {
317 read: properties.contains(CharacteristicProperty::Read).then_some(levels.clone()),
318 write: properties.contains(CharacteristicProperty::Write).then_some(levels.clone()),
319 update: (!properties.is_disjoint(¬ify_properties)).then_some(levels.clone()),
320 }
321 }
322}
323
324#[derive(Clone, Debug)]
335pub enum DescriptorType {
336 UserDescription(String),
337 ServerConfiguration {
338 broadcast: bool,
339 },
340 CharacteristicPresentation {
341 format: u8,
342 exponent: i8,
343 unit: u16,
344 name_space: u8,
345 description: u16,
346 },
347 Other {
348 uuid: Uuid,
349 },
350}
351
352impl From<&DescriptorType> for Uuid {
353 fn from(value: &DescriptorType) -> Self {
354 match value {
356 DescriptorType::UserDescription(_) => Uuid::from_u16(0x2901),
357 DescriptorType::ServerConfiguration { .. } => Uuid::from_u16(0x2903),
358 DescriptorType::CharacteristicPresentation { .. } => Uuid::from_u16(0x2904),
359 DescriptorType::Other { uuid } => uuid.clone(),
360 }
361 }
362}
363
364#[derive(Clone, Debug)]
365pub struct Descriptor {
366 pub handle: Handle,
367 pub permissions: AttributePermissions,
370 pub r#type: DescriptorType,
371}
372
373#[derive(Clone, Debug)]
376pub struct Characteristic {
377 pub handle: Handle,
378 pub uuid: Uuid,
379 pub properties: CharacteristicProperties,
380 pub permissions: AttributePermissions,
382 pub descriptors: Vec<Descriptor>,
383}
384
385impl Characteristic {
386 pub fn properties(&self) -> &CharacteristicProperties {
387 &self.properties
388 }
389
390 pub fn supports_property(&self, property: &CharacteristicProperty) -> bool {
391 self.properties.0.contains(property)
392 }
393
394 pub fn descriptors(&self) -> impl Iterator<Item = &Descriptor> {
395 self.descriptors.iter()
396 }
397
398 pub fn handles(&self) -> impl Iterator<Item = Handle> + '_ {
399 std::iter::once(self.handle).chain(self.descriptors.iter().map(|d| d.handle))
400 }
401}