• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use async_trait::async_trait;
2 use bitflags::bitflags;
3 
4 use crate::core::uuid::Uuid;
5 use crate::gatt::ids::AttHandle;
6 use crate::packets::att::{self, AttErrorCode};
7 
8 impl From<att::AttHandle> for AttHandle {
from(value: att::AttHandle) -> Self9     fn from(value: att::AttHandle) -> Self {
10         AttHandle(value.handle)
11     }
12 }
13 
14 impl From<AttHandle> for att::AttHandle {
from(value: AttHandle) -> Self15     fn from(value: AttHandle) -> Self {
16         att::AttHandle { handle: value.0 }
17     }
18 }
19 
20 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
21 pub struct AttAttribute {
22     pub handle: AttHandle,
23     pub type_: Uuid,
24     pub permissions: AttPermissions,
25 }
26 
27 bitflags! {
28     /// The attribute properties supported by the current GATT server implementation
29     /// Unimplemented properties will default to false.
30     ///
31     /// These values are from Core Spec 5.3 Vol 3G 3.3.1.1 Characteristic Properties,
32     /// and also match what Android uses in JNI.
33     #[derive(Copy, Clone, Debug, PartialEq, Eq)]
34     pub struct AttPermissions : u8 {
35         /// Attribute can be read using READ_REQ
36         const READABLE = 0x02;
37         /// Attribute can be written to using WRITE_CMD
38         const WRITABLE_WITHOUT_RESPONSE = 0x04;
39         /// Attribute can be written to using WRITE_REQ
40         const WRITABLE_WITH_RESPONSE = 0x08;
41         /// Attribute value may be sent using indications
42         const INDICATE = 0x20;
43     }
44 }
45 
46 impl AttPermissions {
47     /// Attribute can be read using READ_REQ
readable(&self) -> bool48     pub fn readable(&self) -> bool {
49         self.contains(AttPermissions::READABLE)
50     }
51     /// Attribute can be written to using WRITE_REQ
writable_with_response(&self) -> bool52     pub fn writable_with_response(&self) -> bool {
53         self.contains(AttPermissions::WRITABLE_WITH_RESPONSE)
54     }
55     /// Attribute can be written to using WRITE_CMD
writable_without_response(&self) -> bool56     pub fn writable_without_response(&self) -> bool {
57         self.contains(AttPermissions::WRITABLE_WITHOUT_RESPONSE)
58     }
59     /// Attribute value may be sent using indications
indicate(&self) -> bool60     pub fn indicate(&self) -> bool {
61         self.contains(AttPermissions::INDICATE)
62     }
63 }
64 
65 #[async_trait(?Send)]
66 pub trait AttDatabase {
67     /// Read an attribute by handle
read_attribute(&self, handle: AttHandle) -> Result<Vec<u8>, AttErrorCode>68     async fn read_attribute(&self, handle: AttHandle) -> Result<Vec<u8>, AttErrorCode>;
69 
70     /// Write to an attribute by handle
write_attribute(&self, handle: AttHandle, data: &[u8]) -> Result<(), AttErrorCode>71     async fn write_attribute(&self, handle: AttHandle, data: &[u8]) -> Result<(), AttErrorCode>;
72 
73     /// Write to an attribute by handle
write_no_response_attribute(&self, handle: AttHandle, data: &[u8])74     fn write_no_response_attribute(&self, handle: AttHandle, data: &[u8]);
75 
76     /// List all the attributes in this database.
77     ///
78     /// Expected to return them in sorted order.
list_attributes(&self) -> Vec<AttAttribute>79     fn list_attributes(&self) -> Vec<AttAttribute>;
80 
81     /// Produce an implementation of StableAttDatabase
snapshot(&self) -> SnapshottedAttDatabase<'_> where Self: Sized,82     fn snapshot(&self) -> SnapshottedAttDatabase<'_>
83     where
84         Self: Sized,
85     {
86         SnapshottedAttDatabase { attributes: self.list_attributes(), backing: self }
87     }
88 }
89 
90 /// Marker trait indicating that the backing attribute list of this
91 /// database is guaranteed to remain unchanged across async points.
92 ///
93 /// Useful if we want to call list_attributes() multiple times, rather than
94 /// caching its result the first time.
95 pub trait StableAttDatabase: AttDatabase {
find_attribute(&self, handle: AttHandle) -> Option<AttAttribute>96     fn find_attribute(&self, handle: AttHandle) -> Option<AttAttribute> {
97         self.list_attributes().into_iter().find(|attr| attr.handle == handle)
98     }
99 }
100 
101 /// A snapshot of an AttDatabase implementing StableAttDatabase.
102 pub struct SnapshottedAttDatabase<'a> {
103     attributes: Vec<AttAttribute>,
104     backing: &'a (dyn AttDatabase),
105 }
106 
107 #[async_trait(?Send)]
108 impl AttDatabase for SnapshottedAttDatabase<'_> {
read_attribute(&self, handle: AttHandle) -> Result<Vec<u8>, AttErrorCode>109     async fn read_attribute(&self, handle: AttHandle) -> Result<Vec<u8>, AttErrorCode> {
110         self.backing.read_attribute(handle).await
111     }
112 
write_attribute(&self, handle: AttHandle, data: &[u8]) -> Result<(), AttErrorCode>113     async fn write_attribute(&self, handle: AttHandle, data: &[u8]) -> Result<(), AttErrorCode> {
114         self.backing.write_attribute(handle, data).await
115     }
116 
write_no_response_attribute(&self, handle: AttHandle, data: &[u8])117     fn write_no_response_attribute(&self, handle: AttHandle, data: &[u8]) {
118         self.backing.write_no_response_attribute(handle, data);
119     }
120 
list_attributes(&self) -> Vec<AttAttribute>121     fn list_attributes(&self) -> Vec<AttAttribute> {
122         self.attributes.clone()
123     }
124 }
125 
126 impl StableAttDatabase for SnapshottedAttDatabase<'_> {}
127