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