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